
บทนำ
ในบทความนี้ คุณจะได้เรียนรู้วิธีใช้ฟังก์ชัน fork() และ exec() เพื่อสร้าง รัน หรือแทนที่กระบวนการ (process) ด้วยอีกกระบวนการหนึ่ง เราจะอธิบายรายละเอียดของทั้งสองฟังก์ชัน ไวยากรณ์ วิธีการเรียกใช้ ตัวอย่างปฏิบัติสั้นๆ และวิธีการรวม fork() กับ execv() เพื่อสร้างกระบวนการใหม่และแทนที่ด้วยอีกตัวหนึ่ง
ฟังก์ชัน fork() ในภาษา C
ฟังก์ชัน fork() สร้างกระบวนการลูก (child process) ที่เป็นโคลนของกระบวนการแม่ (parent process) แม้กระบวนการลูกจะเป็นสำเนาของกระบวนการแม่ แต่ทั้งสองไม่ได้แบ่งปันคุณสมบัติบางอย่าง เช่น พื้นที่หน่วยความจำที่จัดสรร PID และอื่นๆ
ไวยากรณ์ของ fork()
pid_t fork(void);
ค่าส่งกลับของ fork()
- ในกระบวนการแม่: คืนค่า PID ของกระบวนการลูก
- ในกระบวนการลูก: คืนค่า 0
กลไกนี้ช่วยให้เราสามารถรันโค้ดที่ต่างกันในแต่ละกระบวนการผ่านเงื่อนไข if:
if (fork() == 0) {
// โค้ดสำหรับกระบวนการลูก
} else {
// โค้ดสำหรับกระบวนการแม่
}
ตัวอย่างการใช้งาน fork()
#include <stdio.h>
#include <unistd.h>
void main() {
if (fork() == 0) {
// กระบวนการลูก
while (1) {
printf("Write by child process \n");
sleep(5);
}
} else {
// กระบวนการแม่
while (1) {
printf("Write by parent process \n");
sleep(2);
}
}
}

จากภาพ ผลลัพธ์แสดงว่าแต่ละกระบวนการรันโค้ดที่ต่างกันไป กระบวนการลูกพิมพ์ข้อความทุก 5 วินาที ส่วนกระบวนการแม่พิมพ์ทุก 2 วินาที
กลุ่มฟังก์ชัน execXXX() ในภาษา C
กลุ่มฟังก์ชัน execXXX() ใช้สำหรับแทนที่กระบวนการที่กำลังทำงานอยู่ด้วยกระบวนการใหม่ รูปภาพของกระบวนการใหม่จะถูกคัดลอกเข้าไปในพื้นที่หน่วยความจำที่จัดสรรให้กระบวนการเดิม โดยรักษา PID และทรัพยากรที่จัดสรรไว้
ฟังก์ชันในกลุ่มนี้ (ประกาศใน unistd.h) มีวิธีการเรียกใช้ที่แตกต่างกันตามอินพุต และเป็นแบบ "variadics" สามารถส่งอาร์กิวเมนต์หรือพอยน์เตอร์จากกระบวนการเก่าไปยังกระบวนการใหม่ได้
ไวยากรณ์ของแต่ละฟังก์ชัน
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 *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
ความแตกต่างของแต่ละฟังก์ชัน
| ฟังก์ชัน | พารามิเตอร์แรก | พารามิเตอร์ที่สอง | Environment |
|---|---|---|---|
| execl, execle, execv | Absolute path ของ executable | รายการอาร์กิวเมนต์ (string หรือ array) | execle รองรับ envp |
| execlp, execvp, execvpe | ชื่อไฟล์ใน PATH | รายการอาร์กิวเมนต์ | execvpe รองรับ envp |
ตัวอย่างการใช้งาน execv()
เราจะสร้าง 2 โปรแกรม: กระบวนการแม่ เรียก execv() เพื่อแทนที่ตัวเองด้วยกระบวนการลูก และส่งอาร์กิวเมนต์ 2 ตัวไปให้ลูก
กระบวนการลูก (child.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
printf("I am the child process\n\n");
printf("Argument 1: %s\n", argv[1]);
printf("Argument 2: %s\n", argv[2]);
return 0;
}
คอมไพล์และบันทึกเป็น executable:
~$ gcc Documents/child.c -o Documents/child.bin
กระบวนการแม่ (parent.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main() {
printf("I am the parent process");
char *arg_Ptr[4];
// ตามข้อกำหนด: arg[0] = ชื่อโปรแกรม, arg[last] = NULL
arg_Ptr[0] = "child.bin";
arg_Ptr[1] = " Hello from ";
arg_Ptr[2] = " process 2 ";
arg_Ptr[3] = NULL;
execv("/home/linuxhint/Documents/child.bin", arg_Ptr);
// ถ้ามาถึงบรรทัดนี้ แสดงว่า execv ล้มเหลว
perror("execv failed");
return 1;
}
คอมไพล์และรัน:
~$ gcc Documents/parent.c -o parent
~$ ./parent

กระบวนการแม่แสดงข้อความ สร้างอาร์เรย์สตริง เรียก execv() และถ้า execv() สำเร็จ กระบวนการลูก (child.bin) จะแทนที่กระบวนการแม่ รักษา PID และหน่วยความจำเดิม กระบวนการลูกจะแสดงข้อความและอาร์กิวเมนต์ที่ได้รับ
การรวม fork() และ execve() เพื่อสร้างกระบวนการใหม่ใน Linux
เราสามารถรวมทั้งสองฟังก์ชัน: fork() สร้างกระบวนการลูก แล้ว execve() แทนที่กระบวนการลูกด้วย executable ใหม่
#include <stdio.h>
#include <unistd.h>
void main() {
if (fork() == 0) {
// กระบวนการลูก: แทนที่ด้วย child.bin
printf("I am the child process\n");
char *arg_Ptr[5];
arg_Ptr[0] = "child.bin";
arg_Ptr[1] = " Hello from ";
arg_Ptr[2] = " process 2 ";
arg_Ptr[3] = NULL;
execv("/home/linuxhint/Documents/child.bin", arg_Ptr);
} else {
// กระบวนการแม่: ทำงานต่อไป
while (1) {
printf("Write by parent process \n");
sleep(3);
}
}
}

จากภาพ fork() สร้างกระบวนการใหม่โดยการโคลน แล้ว execv() แทนที่กระบวนการลูกด้วย child.bin
สรุป
บทความนี้ได้แสดงวิธีใช้ fork() และ execv() เพื่อเปิดกระบวนการใหม่ใน Linux อธิบายรายละเอียด ไวยากรณ์ อาร์กิวเมนต์นำเข้า/ส่งออก ตัวอย่างแต่ละฟังก์ชัน และวิธีรวมใช้งานร่วมกัน ซึ่งเป็นวิธีมาตรฐานของภาษา C ในการสร้างกระบวนการใหม่ใน Linux