Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม C

เรียนรู้ fork() และ exec() ในภาษา C: การสร้างและแทนที่กระบวนการ

เรียนรู้ fork() และ exec() ในภาษา C: การสร้างและแทนที่กระบวนการ

บทนำ

ในบทความนี้ คุณจะได้เรียนรู้วิธีใช้ฟังก์ชัน 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);
        }
    }
}

เรียนรู้ fork() และ exec() ในภาษา C: การสร้างและแทนที่กระบวนการ

จากภาพ ผลลัพธ์แสดงว่าแต่ละกระบวนการรันโค้ดที่ต่างกันไป กระบวนการลูกพิมพ์ข้อความทุก 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, execvAbsolute 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

เรียนรู้ fork() และ exec() ในภาษา C: การสร้างและแทนที่กระบวนการ

กระบวนการแม่แสดงข้อความ สร้างอาร์เรย์สตริง เรียก 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() และ exec() ในภาษา C: การสร้างและแทนที่กระบวนการ

จากภาพ fork() สร้างกระบวนการใหม่โดยการโคลน แล้ว execv() แทนที่กระบวนการลูกด้วย child.bin

สรุป

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