এই লিনাক্সহিন্ট নিবন্ধে, আপনি শিখবেন কীভাবে একটি প্রক্রিয়া তৈরি, চালানো বা প্রতিস্থাপন করতে ফর্ক() এবং exec() ফাংশন ব্যবহার করতে হয়। আমরা এই দুটি ফাংশনের একটি বিবরণ দেখব এবং তাদের সিনট্যাক্স এবং কলিং পদ্ধতি ব্যাখ্যা করব। আমরা দুটি ফাংশনের প্রতিটির একটি সংক্ষিপ্ত ব্যবহারিক উদাহরণও দেখব। তারপরে আমরা ব্যাখ্যা করব কিভাবে ফর্ক() এবং execv() একত্রে একটি প্রক্রিয়া তৈরি করতে এবং এটিকে অন্যটির সাথে প্রতিস্থাপন করতে হয়৷
C ভাষায় ফর্ক() ফাংশন
ফর্ক() ফাংশন কলিং প্রক্রিয়ার একটি নকল তৈরি করে। যদিও চাইল্ড প্রসেসটি প্যারেন্ট প্রসেসের একটি ডুপ্লিকেট, তারা নির্দিষ্ট কিছু বৈশিষ্ট্য যেমন বরাদ্দ করা মেমরি এরিয়া, পিআইডি ইত্যাদি শেয়ার করে না। এরপরে, ফর্ক() ফাংশনের সিনট্যাক্স দেখি:
ফর্ক() ফাংশন প্যারেন্ট প্রসেসের ফলস্বরূপ চাইল্ড প্রসেসের পিআইডি রিটার্ন করে, যখন একই কল চাইল্ড প্রসেসে কোন প্রভাব ফেলে না এবং ফলস্বরূপ 0 রিটার্ন করে। এই মেকানিজমটি আমাদেরকে একটি "if" কন্ডিশনের মাধ্যমে দুটি প্রসেসে বিভিন্ন কোড এক্সিকিউট করতে দেয় যেখানে কন্ডিশন হল ফর্ক() এর রিটার্ন ভ্যালু। আসুন এই নিম্নলিখিত ধারণাটি দেখি:
যদি (কাঁটা() ==0)
{
শিশু প্রক্রিয়ার জন্য কোড
অন্য
{
পিতামাতার প্রক্রিয়ার জন্য কোড
এইভাবে, প্যারেন্ট প্রসেস কোডটি এক্সিকিউট করে যা "অন্য" স্টেটমেন্টের কোঁকড়া বন্ধনীর মধ্যে থাকে, যখন চাইল্ড প্রসেস "if" স্টেটমেন্টে থাকা কোডটি এক্সিকিউট করে।
একটি সহজ উদাহরণ দিয়ে এটি দেখা যাক। নিম্নলিখিত কোডটি আমরা দেখতে পাচ্ছি দুটি অসীম লুপ নিয়ে গঠিত। প্যারেন্ট প্রসেসে, প্রোগ্রামটি লুপে পড়ে "অন্য" স্টেটমেন্টের সাথে সঙ্গতিপূর্ণ যা "অভিভাবক প্রক্রিয়ার জন্য লিখুন" বার্তা প্রদর্শন করে, যখন ফর্ক() দ্বারা তৈরি চাইল্ড প্রসেসটি "যদি" বিবৃতিতে পড়ে যা "শিশু প্রক্রিয়ার জন্য লিখুন" বার্তা প্রদর্শন করে।
# অন্তর্ভুক্ত করুন
#include
void main(){
যদি (কাঁটা() ==0)
{
যখন (1){
printf ("শিশু প্রক্রিয়া দ্বারা লিখুন \n");
ঘুম (5);}
অন্য
{
যখন (1){
printf ("অভিভাবক প্রক্রিয়া দ্বারা লিখুন \n");
ঘুম (2);}
}
নিম্নলিখিত চিত্রটি এই কোডটির সংকলন এবং সম্পাদন দেখায়। কমান্ড কনসোলে যেমন দেখা যায়, প্রতিটি প্রসেস ভিন্ন ভিন্ন কোড নির্বাহ করে:

C ভাষায় ExecXXX() ফাংশন
execXXX() ফাংশন পরিবার একটি চলমান প্রক্রিয়াকে একটি নতুন প্রক্রিয়ার সাথে প্রতিস্থাপন করে। নতুন প্রক্রিয়াটির চিত্রটি মেমরি এলাকায় অনুলিপি করা হয় যা প্রতিস্থাপন করা প্রক্রিয়ার জন্য বরাদ্দ করা হয়, অন্যান্য জিনিসগুলির মধ্যে সংরক্ষণ করা হয়, এর পিআইডি এবং বরাদ্দ করা সংস্থান৷
এই গ্রুপের ফাংশনগুলি যা "unistd.h" হেডারে সংজ্ঞায়িত করা হয়েছে সেগুলি তাদের ইনপুটগুলির উপর নির্ভর করে বিভিন্ন কল পদ্ধতি ব্যবহার করে এবং "ভেরিয়েডিক্স" টাইপের হয়, তাই তারা পুরানো প্রক্রিয়া থেকে নতুনটিতে আর্গুমেন্ট বা পয়েন্টারগুলির একটি অনির্দিষ্ট তালিকা পাস করতে পারে। এর পরে, আসুন প্রতিটি ফাংশনের জন্য সিনট্যাক্স দেখি।
int execl(const char *path, const char *arg, ...(char *) NULL );
int execlp(const char *file, const char *arg, ... (char *) NULL );
int execle(const char *path, const char *arg, ... , (char *) NULL, char * const envp[] );
int execv(const char *পথ, char *const argv[]);
int execvp(const char *ফাইল, char *const argv[]);
int execvpe(const char *ফাইল, char *const argv[],
char *const envp[]);
execl(), execle(), এবং execv() ফাংশনগুলি একটি স্ট্রিংকে তাদের প্রথম ইনপুট আর্গুমেন্ট হিসাবে একটি পয়েন্টার ব্যবহার করে যাতে নতুন প্রক্রিয়ার এক্সিকিউটেবল ফাইলের পরম পাথ থাকে, যখন execlp(), execvp(), এবং execvpe() বর্তমান ডিরেক্টরিতে ফাইলের নাম ব্যবহার করে। দ্বিতীয় ইনপুট হল আর্গুমেন্ট যা আপনি নতুন প্রক্রিয়ায় পাস করেন। এগুলো অবশ্যই হয় const char *arg স্ট্রিং অথবা char *const argv[] স্ট্রিং-এর পয়েন্টারগুলির তালিকা হতে হবে।
এখন, আসুন একটি উদাহরণ দেখি যা একটি প্রক্রিয়া প্রতিস্থাপন করতে এবং একটি প্রোগ্রাম থেকে অন্য প্রোগ্রামে ইনপুট আর্গুমেন্টগুলি পাস করতে execv() ফাংশন ব্যবহার করে৷
এটি করার জন্য, আমরা দুটি খুব সাধারণ কোড তৈরি করি। একটি হল প্যারেন্ট প্রসেস যা execv() ফাংশনকে চাইল্ড প্রসেস এক্সিকিউট করার জন্য কল করে। যখন execv() ফাংশন চাইল্ড প্রসেস শুরু করে, তখন এটি একটি স্ট্রিং আকারে দুটি ইনপুট আর্গুমেন্ট পাস করে যা চাইল্ড প্রসেস পুনরুদ্ধার করবে এবং শেলে প্রদর্শন করবে।
শিশু প্রক্রিয়া
চাইল্ড প্রসেস হল একটি সাধারণ কোডের টুকরো যা "আমি চাইল্ড প্রসেস" বার্তাটি প্রিন্ট করে, প্যারেন্ট প্রসেস দ্বারা প্রেরিত ইনপুট আর্গুমেন্ট পুনরুদ্ধার করে এবং সেগুলিকে শেলে প্রদর্শন করে৷ এখানে চাইল্ড প্রসেসের কোড আছে:
# অন্তর্ভুক্ত করুন
# অন্তর্ভুক্ত করুন
#include
int main(int argc, char *argv[])
{
printf ("আমি চাইল্ড প্রসেস\n\n");
printf ("আর্গুমেন্ট 1:%s\n", argv[1]);
printf ("আর্গুমেন্ট 2:%s\n", argv[2]);
}
আমরা এই কোডটি কম্পাইল করি এবং "শিশু" নামের অধীনে "ডকুমেন্টস" এ এটির প্রোডাকশন সংরক্ষণ করি ".bin" এক্সটেনশনের সাথে নিম্নলিখিত হিসাবে দেখানো হয়েছে:
~$ gcc ডকুমেন্টস/child.c -o ডকুমেন্টস/child.bin
এইভাবে, আমরা চাইল্ড এক্সিকিউটেবল ফাইলটিকে "ডকুমেন্টস"-এ সংরক্ষণ করি। এই এক্সিকিউটেবলের পাথ হল ইনপুট আর্গুমেন্ট পাথ যখন প্যারেন্ট প্রসেসে execv() কল করা হয়।
অভিভাবক প্রক্রিয়া
প্যারেন্ট প্রসেস হল সেই একটি যা থেকে আমরা execv() ফাংশনটিকে চাইল্ড প্রসেস দিয়ে প্রতিস্থাপন করতে বলি। এই কোডে, আমরা স্ট্রিংগুলিতে পয়েন্টারগুলির একটি অ্যারে সংজ্ঞায়িত করি যা execv() ফাংশনটি খোলার প্রক্রিয়ার ইনপুট আর্গুমেন্টগুলিকে উপস্থাপন করে৷
নিম্নলিখিত চিত্রে, আপনি দেখতে পারেন কিভাবে সঠিকভাবে স্ট্রিংগুলিতে পয়েন্টারগুলির একটি অ্যারে তৈরি করতে হয়। এই ক্ষেত্রে, এটি চারটি পয়েন্টার নিয়ে গঠিত এবং একে "arg_Ptr[]" বলা হয়।
পয়েন্টার অ্যারে সংজ্ঞায়িত হয়ে গেলে, প্রতিটি পয়েন্টারকে অবশ্যই একটি স্ট্রিং দিয়ে বরাদ্দ করতে হবে যাতে ইনপুট আর্গুমেন্ট থাকে যা আমরা চাইল্ড প্রসেসে পাঠাই। execxx() ফাংশন ব্যবহার করার জন্য একটি সাধারণ নিয়ম হিসাবে, প্রথম আর্গুমেন্টটি একটি স্ট্রিং হওয়া উচিত যাতে এক্সিকিউটেবল ফাইলের নাম এবং এক্সটেনশন থাকে এবং শেষ পয়েন্টারটি NULL হওয়া উচিত৷
এইভাবে, আমরা প্রতিটি পয়েন্টারে একটি স্ট্রিং বিন্যাসে সংশ্লিষ্ট আর্গুমেন্ট বরাদ্দ করি:
arg_Ptr[0] ="child.bin";
arg_Ptr[1] ="হ্যালো থেকে";
arg_Ptr[2] ="প্রক্রিয়া 2";
arg_Ptr[3] =NULL;
পরবর্তী ধাপ হল execv() ফাংশনকে কল করা, প্রথম আর্গুমেন্ট হিসেবে এক্সিকিউটেবল ফাইলের পরম পাথ এবং দ্বিতীয় আর্গুমেন্ট হিসেবে arg_Ptr[] এর অ্যারে ধারণ করে এমন স্ট্রিং পাস করা। আপনি নিম্নলিখিত প্যারেন্ট প্রক্রিয়ার সম্পূর্ণ কোড দেখতে পারেন:
# অন্তর্ভুক্ত
#include
#include
#include
#include
int প্রধান (){
printf ("আমি অভিভাবক প্রক্রিয়া");
char *arg_Ptr[4];
arg_Ptr[0] ="child.c";
arg_Ptr[1] ="হ্যালো থেকে";
arg_Ptr[2] ="প্রক্রিয়া 2";
arg_Ptr[3] =NULL;
execv("/home/linuxhint/Documents/child.bin", arg_Ptr);
}
আমরা এই কোডটি কম্পাইল করি যা “.c” ফাইলের পথ এবং আউটপুটের নাম নির্দিষ্ট করে:
~$ gcc ডকুমেন্টস/parent.c -o প্যাটার্ন
তারপর, আমরা আউটপুট চালাই:
অভিভাবক প্রক্রিয়াটি "আমিই অভিভাবক প্রক্রিয়া" বার্তাটি প্রদর্শন করে, পরবর্তী প্রক্রিয়াতে পাস করা প্রতিটি ইনপুট আর্গুমেন্টের জন্য একটি স্ট্রিং বরাদ্দ করে স্ট্রিং অ্যারে তৈরি করে এবং execv() ফাংশনকে কল করে৷
যদি execv() ফাংশন সফলভাবে সঞ্চালিত হয়, তাহলে "child.bin" এক্সিকিউটেবল প্যারেন্ট প্রসেস প্রতিস্থাপন করে এবং এর আইডি এবং বরাদ্দ করা মেমরি গ্রহণ করে। সুতরাং, এই ক্রিয়াটি পূর্বাবস্থায় ফেরানো যাবে না৷
৷চাইল্ড প্রসেস "আমিই চাইল্ড প্রসেস" বার্তাটি প্রদর্শন করে এবং কমান্ড কনসোলে প্রদর্শনের জন্য প্যারেন্ট প্রসেস দ্বারা পাস করা প্রতিটি ইনপুট আর্গুমেন্ট পুনরুদ্ধার করে৷

লিনাক্সে নতুন প্রসেস তৈরি করার জন্য ফর্ক() এবং Execve() ফাংশনগুলি একত্রিত করে
আমরা এখন পর্যন্ত দেখেছি, fork() ফাংশন একটি প্রক্রিয়ার নকল করে, যখন execve() একটি প্রক্রিয়া প্রতিস্থাপন করে। এই উদাহরণে, আমরা দেখব কিভাবে আমরা এই দুটি ফাংশনকে একত্রিত করে ব্যবহার করতে পারি একটি সদৃশ থেকে একটি নতুন প্রক্রিয়া খুলতে যা তারপর প্রতিস্থাপিত হয়। এটি করার জন্য, আমরা দুটি ফাংশন থেকে কোডটি একত্রিত করি যা আমরা আগে দেখেছি যাতে ফর্ক() প্যারেন্ট প্রক্রিয়ার নকল করে এবং execve() এটিকে একটি এক্সিকিউটেবল দিয়ে প্রতিস্থাপন করে যা এই ক্ষেত্রে, আমরা আগের "child.bin" উদাহরণে ব্যবহার করেছিলাম।
এখন, আমরা ".c" এক্সটেনশন সহ একটি খালি ফাইল নিই এবং প্রোগ্রাম কোডটি সন্নিবেশ করি যা আমরা ফর্ক() ফাংশনের উদাহরণে দেখেছি৷
এই প্রোগ্রামে, আমরা শুধুমাত্র চাইল্ড প্রসেসের কোড পরিবর্তন করি যাতে execv() ফাংশন এটিকে "child.bin" এক্সিকিউটেবল দিয়ে প্রতিস্থাপন করে, যখন মূল কাজটি fork() ফাংশনের উদাহরণের অনুরূপ।
এটি করার জন্য, আমরা execv() ফাংশন উদাহরণ থেকে main() ফাংশনের বিষয়বস্তু অনুলিপি করি এবং এই কোড দিয়ে “if” স্টেটমেন্টের বিষয়বস্তু প্রতিস্থাপন করি। এখন, দেখা যাক সম্পূর্ণ প্রোগ্রামটি কেমন দেখায়:
# অন্তর্ভুক্ত করুন
#include
void main(){
যদি (কাঁটা() ==0)
{
printf ("আমি চাইল্ড প্রসেস\n");
char *arg_Ptr[5];
arg_Ptr[0] ="child.c";
arg_Ptr[1] ="হ্যালো থেকে";
arg_Ptr[2] ="প্রক্রিয়া 2";
arg_Ptr[3] =NULL;
execv(/home/linuxhint/Documents/child.bin", arg_Ptr);
অন্য
{
যখন (1){
printf ("
ঘুম (3);}
}
}
এইভাবে, সিস্টেমে একটি নতুন তৈরি করে প্রক্রিয়াটি নকল করা হয় যা execv() ফাংশন তারপর "child.bin" এক্সিকিউটেবল থেকে প্রক্রিয়াটির সাথে প্রতিস্থাপন করে। এর পরে, আমরা এই কোডের সংকলন সহ একটি চিত্র দেখতে পাচ্ছি।

আমরা ছবিতে দেখতে পাচ্ছি, ফর্ক() ফাংশনটি ডুপ্লিকেট করে একটি নতুন প্রক্রিয়া তৈরি করে, যেটি execv() ফাংশন তারপর "child.bin" এক্সিকিউটেবল দিয়ে প্রতিস্থাপিত হয়৷
উপসংহার
এই লিনাক্সহিন্ট নিবন্ধে, আমরা আপনাকে দেখিয়েছি কিভাবে লিনাক্সে নতুন প্রসেস খুলতে ফর্ক() এবং execv() ফাংশন ব্যবহার করতে হয়। আমরা আপনাকে এই প্রতিটি ফাংশন, তাদের সিনট্যাক্স এবং ইনপুট এবং আউটপুট আর্গুমেন্টের একটি সংক্ষিপ্ত বিবরণ দেখিয়েছি। এটি কীভাবে কাজ করে তা আরও ভালভাবে বুঝতে আপনাকে সাহায্য করার জন্য, আমরা এই ফাংশনগুলির প্রতিটির একটি উদাহরণও অন্তর্ভুক্ত করেছি যেখানে আমরা তাদের কল পদ্ধতি এবং তাদের প্রত্যেকের কার্য সম্পাদন শিখেছি। এই দুটি ফাংশনকে পৃথকভাবে দেখার পর, আমরা ব্যাখ্যা করেছি যে লিনাক্সে নতুন প্রসেস তৈরি করার জন্য সি ল্যাঙ্গুয়েজ যে পদ্ধতিটি প্রদান করে তা বাস্তবায়নের জন্য কীভাবে এগুলিকে একত্রে ব্যবহার করতে হয়।