精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Linux 進(jìn)程編程核心:fork、wait 和 exec 深度解析

系統(tǒng) Linux
在進(jìn)程編程中,fork、wait和exec是三個(gè)非常關(guān)鍵的函數(shù),它們分別用于創(chuàng)建新進(jìn)程、等待子進(jìn)程結(jié)束和執(zhí)行新的程序。接下來,我們將深入探討這三個(gè)函數(shù)的用法和原理。

在 Linux 系統(tǒng)中,進(jìn)程是程序的一次執(zhí)行過程,是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。每個(gè)進(jìn)程都有自己獨(dú)立的地址空間、文件描述符、寄存器等資源,操作系統(tǒng)通過進(jìn)程控制塊(PCB,在 Linux 內(nèi)核中用task_struct結(jié)構(gòu)體表示)來管理進(jìn)程的相關(guān)信息。

進(jìn)程在操作系統(tǒng)中扮演著至關(guān)重要的角色,它是操作系統(tǒng)實(shí)現(xiàn)多任務(wù)處理的基礎(chǔ)。通過進(jìn)程,操作系統(tǒng)可以同時(shí)運(yùn)行多個(gè)程序,提高系統(tǒng)的利用率和響應(yīng)速度。例如,當(dāng)我們?cè)?Linux 系統(tǒng)中打開多個(gè)終端窗口,每個(gè)終端窗口都可以看作是一個(gè)獨(dú)立的進(jìn)程,它們可以同時(shí)執(zhí)行不同的命令,互不干擾。

在進(jìn)程編程中,fork、wait和exec是三個(gè)非常關(guān)鍵的函數(shù),它們分別用于創(chuàng)建新進(jìn)程、等待子進(jìn)程結(jié)束和執(zhí)行新的程序。接下來,我們將深入探討這三個(gè)函數(shù)的用法和原理。

一、進(jìn)程創(chuàng)建:fork函數(shù)解析

1. fork 函數(shù)基礎(chǔ)

fork函數(shù)是 Linux 系統(tǒng)中用于創(chuàng)建新進(jìn)程的系統(tǒng)調(diào)用,其定義在<unistd.h>頭文件中 ,原型為pid_t fork(void);。這里的pid_t是一種數(shù)據(jù)類型,用來表示進(jìn)程 ID。fork函數(shù)的功能非常強(qiáng)大,它會(huì)創(chuàng)建一個(gè)與調(diào)用進(jìn)程(即父進(jìn)程)幾乎完全相同的新進(jìn)程,這個(gè)新進(jìn)程被稱為子進(jìn)程。

子進(jìn)程會(huì)復(fù)制父進(jìn)程的代碼段、數(shù)據(jù)段、堆、棧等資源,擁有自己獨(dú)立的進(jìn)程 ID(PID),但與父進(jìn)程共享一些資源,如打開的文件描述符。簡(jiǎn)單來說,就像是父進(jìn)程克隆了一個(gè)自己,這個(gè)克隆體(子進(jìn)程)有著與父進(jìn)程相似的 “外貌”(資源),但又有自己獨(dú)特的 “身份標(biāo)識(shí)”(PID) 。

2. fork 的返回值與執(zhí)行邏輯

fork函數(shù)的一個(gè)獨(dú)特之處在于它會(huì)返回兩次,一次是在父進(jìn)程中,一次是在子進(jìn)程中。在父進(jìn)程中,fork返回子進(jìn)程的 PID;在子進(jìn)程中,fork返回 0。如果fork函數(shù)執(zhí)行失敗,它會(huì)返回 - 1,并設(shè)置errno來指示錯(cuò)誤原因。這種不同的返回值為區(qū)分父子進(jìn)程提供了依據(jù),就像是給父子進(jìn)程分別發(fā)放了不同的 “通行證”,讓它們可以在后續(xù)的代碼中走不同的路徑 。

下面通過一段簡(jiǎn)單的 C 代碼來展示fork函數(shù)的返回值和執(zhí)行邏輯:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    pid_t pid;

    // 調(diào)用fork函數(shù)創(chuàng)建子進(jìn)程
    pid = fork();

    // 判斷fork的返回值
    if (pid < 0) {
        // fork失敗
        perror("fork error");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子進(jìn)程
        printf("I am the child process, my pid is %d, my parent's pid is %d\n", getpid(), getppid());
    } else {
        // 父進(jìn)程
        printf("I am the parent process, my pid is %d, and my child's pid is %d\n", getpid(), pid);
    }

    return 0;
}

在這段代碼中,首先調(diào)用fork函數(shù)創(chuàng)建子進(jìn)程。然后根據(jù)fork的返回值判斷當(dāng)前是父進(jìn)程還是子進(jìn)程。如果返回值小于 0,說明fork失敗,輸出錯(cuò)誤信息并退出程序;如果返回值為 0,說明是子進(jìn)程,輸出子進(jìn)程的 PID 和父進(jìn)程的 PID;如果返回值大于 0,說明是父進(jìn)程,輸出父進(jìn)程的 PID 和子進(jìn)程的 PID。

運(yùn)行這段代碼,你會(huì)看到類似如下的輸出:

I am the parent process, my pid is 12345, and my child's pid is 12346
I am the child process, my pid is 12346, my parent's pid is 12345

從輸出結(jié)果可以清晰地看到父子進(jìn)程的 PID 以及它們的執(zhí)行路徑 。

3. 寫時(shí)復(fù)制機(jī)制

在早期的操作系統(tǒng)中,當(dāng)使用fork創(chuàng)建子進(jìn)程時(shí),會(huì)直接將父進(jìn)程的所有內(nèi)存空間完整地復(fù)制給子進(jìn)程,這在內(nèi)存使用和性能上都存在很大的問題,尤其是對(duì)于大型程序來說,復(fù)制大量?jī)?nèi)存數(shù)據(jù)會(huì)消耗大量時(shí)間和內(nèi)存資源。為了解決這個(gè)問題,Linux 引入了寫時(shí)復(fù)制(Copy - On - Write,COW)技術(shù) 。

寫時(shí)復(fù)制的原理是,在fork創(chuàng)建子進(jìn)程時(shí),內(nèi)核并不立即復(fù)制父進(jìn)程的整個(gè)地址空間,而是讓父進(jìn)程和子進(jìn)程共享同一個(gè)物理內(nèi)存拷貝,同時(shí)將這些共享內(nèi)存頁標(biāo)記為只讀。只有當(dāng)父子進(jìn)程中的某一個(gè)試圖對(duì)共享內(nèi)存頁進(jìn)行寫操作時(shí),才會(huì)觸發(fā)缺頁異常,此時(shí)內(nèi)核會(huì)為需要寫入的進(jìn)程創(chuàng)建該內(nèi)存頁的一個(gè)新副本,然后將新副本的權(quán)限設(shè)置為可寫,進(jìn)程再對(duì)新副本進(jìn)行寫操作 。

例如,假設(shè)父進(jìn)程有一個(gè)數(shù)據(jù)段,其中包含一個(gè)變量x,值為 10。在fork創(chuàng)建子進(jìn)程后,父子進(jìn)程共享這個(gè)數(shù)據(jù)段的物理內(nèi)存頁。當(dāng)父進(jìn)程或者子進(jìn)程想要修改x的值時(shí),就會(huì)觸發(fā)寫時(shí)復(fù)制機(jī)制。內(nèi)核會(huì)為執(zhí)行寫操作的進(jìn)程創(chuàng)建一個(gè)新的數(shù)據(jù)段內(nèi)存頁,將原內(nèi)存頁的數(shù)據(jù)復(fù)制到新頁,然后在新頁上進(jìn)行寫操作。這樣,另一個(gè)進(jìn)程的數(shù)據(jù)段仍然保持不變,實(shí)現(xiàn)了數(shù)據(jù)的獨(dú)立修改 。

寫時(shí)復(fù)制機(jī)制帶來了很多優(yōu)勢(shì):一方面,它顯著提高了fork操作的效率,因?yàn)椴恍枰趧?chuàng)建子進(jìn)程時(shí)立即復(fù)制大量?jī)?nèi)存數(shù)據(jù),減少了創(chuàng)建子進(jìn)程的時(shí)間開銷;另一方面,它有效地節(jié)省了內(nèi)存資源,尤其是在父子進(jìn)程共享大量數(shù)據(jù)且大部分?jǐn)?shù)據(jù)不需要修改的情況下,避免了不必要的內(nèi)存復(fù)制 。

二、進(jìn)程等待:wait函數(shù)解析

1. wait 函數(shù)作用

在 Linux 進(jìn)程編程中,wait函數(shù)是一個(gè)非常重要的函數(shù),它用于父進(jìn)程等待子進(jìn)程結(jié)束 。當(dāng)父進(jìn)程調(diào)用wait函數(shù)時(shí),會(huì)發(fā)生以下事情:首先,父進(jìn)程會(huì)被阻塞,暫停執(zhí)行,直到它的一個(gè)子進(jìn)程結(jié)束;然后,wait函數(shù)會(huì)回收子進(jìn)程的資源,包括釋放子進(jìn)程占用的內(nèi)存空間、關(guān)閉子進(jìn)程打開的文件描述符等;最后,wait函數(shù)還會(huì)獲取子進(jìn)程的退出狀態(tài),讓父進(jìn)程了解子進(jìn)程是如何結(jié)束的,比如是正常退出還是異常終止 。

wait函數(shù)對(duì)于資源回收和避免僵尸進(jìn)程的產(chǎn)生具有至關(guān)重要的意義。在 Linux 系統(tǒng)中,每個(gè)進(jìn)程都占用一定的系統(tǒng)資源,如果父進(jìn)程創(chuàng)建了子進(jìn)程后,不等待子進(jìn)程結(jié)束并回收其資源,子進(jìn)程就會(huì)變成僵尸進(jìn)程 。僵尸進(jìn)程雖然已經(jīng)結(jié)束運(yùn)行,但它的進(jìn)程控制塊(PCB)仍然保留在系統(tǒng)中,占用系統(tǒng)資源,長(zhǎng)期積累會(huì)導(dǎo)致系統(tǒng)資源浪費(fèi)和性能下降 。通過wait函數(shù),父進(jìn)程可以及時(shí)回收子進(jìn)程的資源,避免僵尸進(jìn)程的出現(xiàn),確保系統(tǒng)的穩(wěn)定運(yùn)行 。

2. wait 函數(shù)原型與參數(shù)

wait函數(shù)的原型定義在<sys/types.h>和<sys/wait.h>頭文件中,具體原型為pid_t wait(int *status);。其中,pid_t是一種數(shù)據(jù)類型,用于表示進(jìn)程 ID;status是一個(gè)指向整數(shù)的指針,用于存儲(chǔ)子進(jìn)程的退出狀態(tài)信息 。

如果status為NULL,表示父進(jìn)程不關(guān)心子進(jìn)程的退出狀態(tài),只希望等待子進(jìn)程結(jié)束并回收其資源 。如果status不為NULL,wait函數(shù)會(huì)將子進(jìn)程的退出狀態(tài)信息存儲(chǔ)在status指向的整數(shù)中 。通過一些宏定義,可以從這個(gè)整數(shù)中解析出子進(jìn)程的具體退出情況 。常用的宏有:

  • WIFEXITED(status):用于判斷子進(jìn)程是否正常退出,如果正常退出返回非零值 。
  • WEXITSTATUS(status):當(dāng)WIFEXITED(status)為真時(shí),通過這個(gè)宏可以獲取子進(jìn)程正常退出時(shí)的返回值 。
  • WIFSIGNALED(status):判斷子進(jìn)程是否是因?yàn)槭盏叫盘?hào)而異常終止,如果是返回非零值 。
  • WTERMSIG(status):當(dāng)WIFSIGNALED(status)為真時(shí),通過這個(gè)宏可以獲取導(dǎo)致子進(jìn)程異常終止的信號(hào)編號(hào) 。

3. wait 函數(shù)應(yīng)用示例

下面通過一段代碼示例來展示wait函數(shù)的具體應(yīng)用 :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
    pid_t pid;
    int status;

    // 創(chuàng)建子進(jìn)程
    pid = fork();
    if (pid < 0) {
        perror("fork error");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子進(jìn)程
        printf("I am the child process, my pid is %d\n", getpid());
        sleep(2);  // 模擬子進(jìn)程執(zhí)行一些任務(wù)
        exit(3);  // 子進(jìn)程正常退出,返回值為3
    } else {
        // 父進(jìn)程
        printf("I am the parent process, my pid is %d, and my child's pid is %d\n", getpid(), pid);
        // 等待子進(jìn)程結(jié)束
        wait(&status);
        if (WIFEXITED(status)) {
            printf("The child process exited normally, exit status is %d\n", WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("The child process was terminated by a signal, signal number is %d\n", WTERMSIG(status));
        }
    }

    return 0;
}

在這段代碼中,首先使用fork函數(shù)創(chuàng)建子進(jìn)程 。子進(jìn)程打印自己的 PID,然后睡眠 2 秒,最后以返回值 3 正常退出 。父進(jìn)程打印自己和子進(jìn)程的 PID,然后調(diào)用wait函數(shù)等待子進(jìn)程結(jié)束 。當(dāng)子進(jìn)程結(jié)束后,wait函數(shù)返回,通過WIFEXITED和WIFSIGNALED宏判斷子進(jìn)程的退出狀態(tài),并打印相應(yīng)信息 。

運(yùn)行這段代碼,你會(huì)看到類似如下的輸出:

I am the parent process, my pid is 12345, and my child's pid is 12346
I am the child process, my pid is 12346
The child process exited normally, exit status is 3

從輸出結(jié)果可以清晰地看到父子進(jìn)程的執(zhí)行過程以及子進(jìn)程的退出狀態(tài) 。

4. waitpid 函數(shù)拓展

waitpid函數(shù)是wait函數(shù)的擴(kuò)展,它提供了更靈活的等待方式 。waitpid函數(shù)的原型為pid_t waitpid(pid_t pid, int *status, int options); 。與wait函數(shù)相比,waitpid函數(shù)有以下幾個(gè)特點(diǎn):

  • 可以指定等待的子進(jìn)程:pid參數(shù)用于指定要等待的子進(jìn)程的 PID 。當(dāng)pid > 0時(shí),等待進(jìn)程 ID 等于pid的子進(jìn)程;當(dāng)pid = -1時(shí),等待任意子進(jìn)程,此時(shí)waitpid與wait功能相同;當(dāng)pid = 0時(shí),等待和當(dāng)前調(diào)用waitpid函數(shù)的進(jìn)程同一個(gè)進(jìn)程組的所有子進(jìn)程;當(dāng)pid < -1時(shí),等待指定進(jìn)程組內(nèi)的任意子進(jìn)程,其中pid的絕對(duì)值表示進(jìn)程組的 ID 。
  • 可以選擇是否阻塞等待:options參數(shù)用于控制waitpid的行為,常用的選項(xiàng)有WNOHANG(非阻塞模式) 。當(dāng)設(shè)置WNOHANG選項(xiàng)時(shí),如果沒有子進(jìn)程結(jié)束,waitpid函數(shù)會(huì)立即返回 0,而不是阻塞等待;如果有子進(jìn)程結(jié)束,則返回該子進(jìn)程的 PID 。
  • 可以處理更多子進(jìn)程狀態(tài):除了可以獲取子進(jìn)程的正常退出和異常終止?fàn)顟B(tài)外,waitpid函數(shù)還可以通過WUNTRACED選項(xiàng)報(bào)告被跟蹤的子進(jìn)程(即使它們尚未停止),通過WCONTINUED選項(xiàng)報(bào)告被繼續(xù)執(zhí)行的子進(jìn)程(即被SIGCONT信號(hào)繼續(xù)執(zhí)行) 。

waitpid函數(shù)在一些復(fù)雜的場(chǎng)景中非常有用 。例如,當(dāng)父進(jìn)程需要同時(shí)管理多個(gè)子進(jìn)程,并且希望在不阻塞的情況下獲取子進(jìn)程的狀態(tài)時(shí),可以使用waitpid函數(shù)的非阻塞模式 。通過循環(huán)調(diào)用waitpid函數(shù),并設(shè)置WNOHANG選項(xiàng),父進(jìn)程可以在等待子進(jìn)程結(jié)束的同時(shí)繼續(xù)執(zhí)行其他任務(wù) 。

下面是一個(gè)使用waitpid函數(shù)非阻塞等待子進(jìn)程的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
    pid_t pid;
    int status;

    // 創(chuàng)建子進(jìn)程
    pid = fork();
    if (pid < 0) {
        perror("fork error");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子進(jìn)程
        printf("I am the child process, my pid is %d\n", getpid());
        sleep(5);  // 模擬子進(jìn)程執(zhí)行一些任務(wù)
        exit(3);  // 子進(jìn)程正常退出,返回值為3
    } else {
        // 父進(jìn)程
        printf("I am the parent process, my pid is %d, and my child's pid is %d\n", getpid(), pid);
        // 非阻塞等待子進(jìn)程結(jié)束
        while (1) {
            pid_t ret = waitpid(pid, &status, WNOHANG);
            if (ret == 0) {
                // 沒有子進(jìn)程結(jié)束,繼續(xù)執(zhí)行其他任務(wù)
                printf("The child process is still running, I can do other things\n");
                sleep(1);
            } else if (ret == pid) {
                // 子進(jìn)程結(jié)束
                if (WIFEXITED(status)) {
                    printf("The child process exited normally, exit status is %d\n", WEXITSTATUS(status));
                } else if (WIFSIGNALED(status)) {
                    printf("The child process was terminated by a signal, signal number is %d\n", WTERMSIG(status));
                }
                break;
            } else {
                // 錯(cuò)誤情況
                perror("waitpid error");
                break;
            }
        }
    }

    return 0;
}

在這個(gè)示例中,父進(jìn)程使用waitpid函數(shù)并設(shè)置WNOHANG選項(xiàng)非阻塞地等待子進(jìn)程結(jié)束 。在等待過程中,父進(jìn)程可以繼續(xù)執(zhí)行其他任務(wù),每隔 1 秒打印一次提示信息 。當(dāng)子進(jìn)程結(jié)束后,waitpid函數(shù)返回子進(jìn)程的 PID,父進(jìn)程獲取子進(jìn)程的退出狀態(tài)并打印相應(yīng)信息 。運(yùn)行這段代碼,你會(huì)看到父進(jìn)程在等待子進(jìn)程的同時(shí)還能執(zhí)行其他任務(wù),充分展示了waitpid函數(shù)的靈活性 。

三、程序替換:exec函數(shù)解析

1. exec 函數(shù)族概述

在 Linux 進(jìn)程編程中,當(dāng)我們需要讓一個(gè)進(jìn)程去執(zhí)行另一個(gè)不同的程序時(shí),就會(huì)用到exec函數(shù)族 。exec函數(shù)族的功能是用一個(gè)新的程序替換當(dāng)前進(jìn)程的正文段、數(shù)據(jù)段、堆段和棧段,使得當(dāng)前進(jìn)程從新程序的入口點(diǎn)開始執(zhí)行 。簡(jiǎn)單來說,就像是把進(jìn)程原本運(yùn)行的程序 “替換” 成了另一個(gè)程序,就如同給一個(gè)機(jī)器人換上了全新的 “大腦”(程序),讓它執(zhí)行新的任務(wù) 。

需要注意的是,exec函數(shù)族并不會(huì)創(chuàng)建新的進(jìn)程,進(jìn)程的 PID 在執(zhí)行exec前后保持不變 。這意味著,雖然進(jìn)程執(zhí)行的程序發(fā)生了變化,但它在系統(tǒng)中的 “身份標(biāo)識(shí)”(PID)并沒有改變 。例如,當(dāng)我們?cè)诮K端中輸入ls命令時(shí),shell 進(jìn)程會(huì)調(diào)用fork創(chuàng)建一個(gè)子進(jìn)程,然后子進(jìn)程調(diào)用exec函數(shù)族中的某個(gè)函數(shù),將自身替換為ls程序的執(zhí)行,此時(shí)子進(jìn)程的 PID 并沒有改變,只是它開始執(zhí)行l(wèi)s程序的代碼 。

2. exec 函數(shù)原型與參數(shù)

exec函數(shù)族包含多個(gè)函數(shù),它們的原型和功能相似,但在參數(shù)傳遞和查找可執(zhí)行文件的方式上有所不同 。常用的exec函數(shù)原型如下:

#include <unistd.h>

// 使用參數(shù)列表傳遞參數(shù),在指定路徑查找可執(zhí)行文件
int execl(const char *path, const char *arg, ...);

// 使用參數(shù)列表傳遞參數(shù),在PATH環(huán)境變量指定路徑查找可執(zhí)行文件
int execlp(const char *file, const char *arg, ...);

// 使用參數(shù)列表傳遞參數(shù),在指定路徑查找可執(zhí)行文件,并可指定新的環(huán)境變量
int execle(const char *path, const char *arg, ..., char *const envp[]);

// 使用參數(shù)數(shù)組傳遞參數(shù),在指定路徑查找可執(zhí)行文件
int execv(const char *path, char *const argv[]);

// 使用參數(shù)數(shù)組傳遞參數(shù),在PATH環(huán)境變量指定路徑查找可執(zhí)行文件
int execvp(const char *file, char *const argv[]);

// 使用參數(shù)數(shù)組傳遞參數(shù),在PATH環(huán)境變量指定路徑查找可執(zhí)行文件,并可指定新的環(huán)境變量
int execvpe(const char *file, char *const argv[], char *const envp[]);

這些函數(shù)的參數(shù)說明如下:

  • path:指定要執(zhí)行的可執(zhí)行文件的完整路徑,例如/bin/ls 。
  • file:如果參數(shù)中包含/,則視為路徑并在指定路徑下查找可執(zhí)行文件;否則將在PATH環(huán)境變量指定的路徑中查找可執(zhí)行文件,例如ls 。
  • arg:指定傳遞給可執(zhí)行文件的一系列參數(shù),以可變參數(shù)列表的形式傳遞,一般第一個(gè)參數(shù)為可執(zhí)行文件的名稱,且最后一個(gè)參數(shù)必須是NULL,用于表示參數(shù)列表的結(jié)束 。例如,execl("/bin/ls", "ls", "-l", NULL),其中"ls"是可執(zhí)行文件的名稱,"-l"是傳遞給ls命令的參數(shù),NULL表示參數(shù)列表結(jié)束 。
  • argv:指定傳遞給可執(zhí)行文件的一系列參數(shù),以參數(shù)數(shù)組的形式傳遞,數(shù)組的最后一個(gè)元素必須是NULL,用于表示參數(shù)數(shù)組的結(jié)束 。例如,char *argv[] = {"ls", "-l", NULL}; execv("/bin/ls", argv); 。
  • envp:指定新進(jìn)程的環(huán)境變量,是一個(gè)指向字符指針數(shù)組的指針,數(shù)組中的每個(gè)元素都是一個(gè)環(huán)境變量字符串,格式為"變量名=值",最后一個(gè)元素必須是NULL,用于表示環(huán)境變量數(shù)組的結(jié)束 。如果不使用該參數(shù),新進(jìn)程將繼承調(diào)用進(jìn)程的環(huán)境變量 。例如,char *envp[] = {"HELLO=world", "USER=root", NULL}; execle("/bin/echo", "echo", "$HELLO", (char *)NULL, envp); 。

3. exec 函數(shù)應(yīng)用示例

下面通過一個(gè)具體的代碼示例來展示exec函數(shù)的使用 :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    pid_t pid;

    // 創(chuàng)建子進(jìn)程
    pid = fork();
    if (pid < 0) {
        perror("fork error");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子進(jìn)程
        // 使用execlp函數(shù)執(zhí)行l(wèi)s命令,列出當(dāng)前目錄下的文件
        // 第一個(gè)參數(shù)"ls"表示在PATH環(huán)境變量中查找ls程序
        // 第二個(gè)參數(shù)"ls"是傳遞給ls程序的參數(shù),一般第一個(gè)參數(shù)是程序名本身
        // 第三個(gè)參數(shù)"-l"是ls命令的參數(shù),用于以長(zhǎng)格式列出文件
        // 最后一個(gè)參數(shù)NULL表示參數(shù)列表結(jié)束
        if (execlp("ls", "ls", "-l", NULL) == -1) {
            perror("execlp error");
            exit(EXIT_FAILURE);
        }
    } else {
        // 父進(jìn)程
        wait(NULL);  // 等待子進(jìn)程結(jié)束
        printf("Child process has finished.\n");
    }

    return 0;
}

在這段代碼中,首先使用fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程 。在子進(jìn)程中,調(diào)用execlp函數(shù)執(zhí)行l(wèi)s -l命令,用于列出當(dāng)前目錄下的文件 。execlp函數(shù)會(huì)在PATH環(huán)境變量指定的路徑中查找ls程序,并將"ls"、"-l"作為參數(shù)傳遞給ls程序 。如果execlp函數(shù)執(zhí)行失敗,會(huì)打印錯(cuò)誤信息并退出子進(jìn)程 。父進(jìn)程調(diào)用wait函數(shù)等待子進(jìn)程結(jié)束,然后打印提示信息 。運(yùn)行這段代碼,你會(huì)看到子進(jìn)程執(zhí)行l(wèi)s -l命令的輸出結(jié)果,展示了當(dāng)前目錄下文件的詳細(xì)信息 。

四、fork、wait 和 exec 三者之間的協(xié)同

1. 常見應(yīng)用場(chǎng)景

在實(shí)際的 Linux 編程中,fork、wait和exec這三個(gè)函數(shù)通常會(huì)協(xié)同工作,共同完成各種復(fù)雜的任務(wù) 。在 Shell 腳本的實(shí)現(xiàn)中,當(dāng)用戶在終端輸入一條命令,比如ls -l,Shell 進(jìn)程會(huì)首先調(diào)用fork創(chuàng)建一個(gè)子進(jìn)程 。這個(gè)子進(jìn)程繼承了 Shell 進(jìn)程的大部分資源,包括打開的文件描述符等 。然后子進(jìn)程調(diào)用exec函數(shù)族中的某個(gè)函數(shù),比如execlp,將自身替換為ls程序的執(zhí)行 。

此時(shí),子進(jìn)程開始執(zhí)行l(wèi)s程序的代碼,根據(jù)傳入的參數(shù)-l以長(zhǎng)格式列出當(dāng)前目錄下的文件 。而父進(jìn)程(即 Shell 進(jìn)程)則調(diào)用wait函數(shù)等待子進(jìn)程結(jié)束 。當(dāng)子進(jìn)程執(zhí)行完ls命令后,父進(jìn)程從wait函數(shù)返回,繼續(xù)等待用戶輸入下一條命令 。通過這樣的協(xié)同工作,Shell 能夠?qū)崿F(xiàn)對(duì)用戶輸入命令的解析和執(zhí)行 。

在服務(wù)器程序中,比如一個(gè)簡(jiǎn)單的 Web 服務(wù)器,fork、wait和exec的協(xié)同也起著關(guān)鍵作用 。當(dāng)服務(wù)器接收到一個(gè)客戶端的連接請(qǐng)求時(shí),主進(jìn)程會(huì)調(diào)用fork創(chuàng)建一個(gè)子進(jìn)程來處理這個(gè)連接 。子進(jìn)程調(diào)用exec函數(shù)族執(zhí)行處理客戶端請(qǐng)求的程序,比如一個(gè) CGI 腳本或者一個(gè)專門的處理程序 。

在這個(gè)過程中,主進(jìn)程可以繼續(xù)監(jiān)聽其他客戶端的連接請(qǐng)求,而子進(jìn)程負(fù)責(zé)處理當(dāng)前客戶端的具體請(qǐng)求 。當(dāng)子進(jìn)程處理完請(qǐng)求后,主進(jìn)程通過wait函數(shù)回收子進(jìn)程的資源,確保系統(tǒng)資源的有效利用 。通過這種方式,Web 服務(wù)器能夠同時(shí)處理多個(gè)客戶端的請(qǐng)求,提高了服務(wù)器的并發(fā)處理能力 。

2. 代碼實(shí)戰(zhàn)

下面給出一個(gè)完整的代碼示例,展示fork、wait和exec的協(xié)同工作流程 :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
    pid_t pid;
    int status;

    // 創(chuàng)建子進(jìn)程
    pid = fork();
    if (pid < 0) {
        perror("fork error");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子進(jìn)程
        char *argv[] = {"ls", "-l", NULL};
        // 使用execvp函數(shù)執(zhí)行l(wèi)s -l命令
        if (execvp("ls", argv) == -1) {
            perror("execvp error");
            exit(EXIT_FAILURE);
        }
    } else {
        // 父進(jìn)程
        printf("I am the parent process, my pid is %d, and my child's pid is %d\n", getpid(), pid);
        // 等待子進(jìn)程結(jié)束
        wait(&status);
        if (WIFEXITED(status)) {
            printf("The child process exited normally, exit status is %d\n", WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("The child process was terminated by a signal, signal number is %d\n", WTERMSIG(status));
        }
    }

    return 0;
}

代碼執(zhí)行過程如下:

  • 首先,主進(jìn)程調(diào)用fork函數(shù)創(chuàng)建子進(jìn)程 。
  • 在子進(jìn)程中,fork返回 0,然后子進(jìn)程創(chuàng)建一個(gè)包含ls和-l的參數(shù)數(shù)組argv 。接著調(diào)用execvp函數(shù),execvp會(huì)在PATH環(huán)境變量指定的路徑中查找ls程序,并使用argv作為參數(shù)執(zhí)行l(wèi)s -l命令 。如果execvp執(zhí)行成功,子進(jìn)程的代碼段、數(shù)據(jù)段、堆段和棧段會(huì)被ls程序替換,開始執(zhí)行l(wèi)s程序的代碼,輸出當(dāng)前目錄下文件的詳細(xì)信息 。如果execvp執(zhí)行失敗,會(huì)打印錯(cuò)誤信息并退出子進(jìn)程 。
  • 在父進(jìn)程中,fork返回子進(jìn)程的 PID,父進(jìn)程打印自己和子進(jìn)程的 PID 。然后調(diào)用wait函數(shù)等待子進(jìn)程結(jié)束 。當(dāng)子進(jìn)程結(jié)束后,wait函數(shù)返回,父進(jìn)程通過WIFEXITED和WIFSIGNALED宏判斷子進(jìn)程的退出狀態(tài),并打印相應(yīng)信息 。

通過這個(gè)代碼示例,我們可以清晰地看到fork、wait和exec是如何協(xié)同工作的 。fork用于創(chuàng)建子進(jìn)程,為執(zhí)行新程序提供載體;exec用于將子進(jìn)程替換為新的程序執(zhí)行;wait用于父進(jìn)程等待子進(jìn)程結(jié)束并回收其資源,確保系統(tǒng)資源的有效管理 。

責(zé)任編輯:趙寧寧 來源: 深度Linux
相關(guān)推薦

2025-10-28 03:00:00

2024-10-07 08:59:47

sleepwait線程

2023-11-20 22:04:33

2022-04-11 09:39:58

Linux進(jìn)程編程

2025-09-15 06:25:00

2011-06-22 16:50:09

Qt 進(jìn)程 通信機(jī)制

2019-10-14 16:46:48

5G移動(dòng)通信架構(gòu)

2025-10-13 04:00:00

2023-03-05 16:12:41

Linux進(jìn)程線程

2021-07-06 21:30:06

Linux進(jìn)程通信

2010-02-25 10:28:43

Linux進(jìn)程管理

2025-07-28 03:00:00

2010-03-15 18:25:27

Java編程語言

2025-09-04 02:11:00

2024-04-01 08:29:09

Git核心實(shí)例

2024-08-01 17:14:53

2011-08-12 11:23:47

iPhone窗口視圖

2020-09-22 07:35:06

Linux線程進(jìn)程

2012-05-03 08:27:20

Linux進(jìn)程

2009-12-25 15:41:10

Linux shell
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美黄色片免费观看| 性感美女久久精品| 91在线精品播放| 国产亚洲精品码| 日韩影视在线观看| 三级欧美韩日大片在线看| 中文字幕精品av| 成人黄色大片网站| 第一福利在线| 国产精品亚洲人在线观看| 久久久久中文字幕2018| 人妻精品久久久久中文字幕| 国产一区久久精品| 成人av网站大全| 国产精品欧美亚洲777777| 青娱乐国产在线| 啪啪亚洲精品| 精品国产三级a在线观看| 欧美精品成人网| 国产桃色电影在线播放| 国产精品青草久久| 九色视频成人porny| 91精品国产综合久| 日韩电影免费在线看| 韩国福利视频一区| 午夜69成人做爰视频| 欧美精品乱码| 日韩电影大全免费观看2023年上| 久草视频这里只有精品| 川上优的av在线一区二区| 不卡的av电影| 国产精品二区在线观看| 黄色一级片在线| 国产探花一区| 国产视频精品va久久久久久| 特级特黄刘亦菲aaa级| 999色成人| 欧美色电影在线| 十八禁视频网站在线观看| 超碰激情在线| 亚洲高清免费在线| 日本三日本三级少妇三级66| 四虎久久免费| 欧美高清在线一区二区| 欧美日产一区二区三区在线观看| 亚洲av无码片一区二区三区 | 亚洲高清视频在线播放| 精品一区二区三区在线观看国产| 国产精品扒开腿做| 五月天婷婷导航| 久久久国产亚洲精品| 热久久美女精品天天吊色| 五月婷婷激情网| 亚洲免费播放| 97高清免费视频| 男人的天堂一区| 国产情侣一区| 国产成人高清激情视频在线观看| 中文字幕一区在线播放| 久久精品官网| 国产精品极品在线| 中文字幕欧美人妻精品| 美国一区二区三区在线播放 | 欧美亚洲日本网站| 野外性满足hd| 五月激激激综合网色播| 亚洲欧美日韩一区在线| www亚洲色图| 91麻豆精品国产91久久久平台 | 精品国内二区三区| 久久久久久久穴| 免费日韩一区二区三区| 亚洲天堂男人天堂| 亚洲一二三四五六区| 亚洲成人国产| 97超级碰碰碰久久久| 麻豆成人免费视频| 精品一区二区免费在线观看| 91青青草免费在线看| 天天操天天操天天| 国产视频一区不卡| 看全色黄大色大片| 国产高清自产拍av在线| 欧美综合欧美视频| 污视频在线观看免费网站| 精品精品精品| 色婷婷久久av| 日韩欧美大片在线观看| 日本va欧美va瓶| 97自拍视频| 欧美成人综合在线| 国产成人h网站| 免费h精品视频在线播放| 2019中文字幕在线视频| 亚洲国产日日夜夜| 激情五月婷婷久久| 99久热这里只有精品视频免费观看| 欧美午夜宅男影院| 日韩欧美精品在线观看视频| 日本成人在线网站| 亚洲第五色综合网| www中文在线| 亚洲黄色大片| 成人欧美一区二区三区黑人| 日韩一卡二卡在线| 中文字幕一区二区三区在线不卡| 男人插女人视频在线观看| 粉嫩av一区二区三区四区五区 | 91人人澡人人爽| 久草精品在线| 国模吧一区二区| 国产一区二区三区中文字幕 | 成人免费毛片xxx| 久久激情中文| 精品国产一区二区三区四区vr | 综合欧美亚洲日本| 成年人免费大片| 福利电影一区 | 国产理论在线| 欧美一区二区三区的| 亚洲女优在线观看| 亚洲狼人精品一区二区三区| 成人激情电影一区二区| 伦理片一区二区三区| 亚洲成人综合在线| 又黄又爽又色的视频| 日韩激情免费| 国产成人福利网站| 可以免费看污视频的网站在线| 亚洲国产精品久久人人爱 | 精品中文在线| 91精品欧美综合在线观看最新| 国产伦精品一区二区三区妓女| 欧美日本免费| 91免费视频网站| 国产一级片在线播放| 亚洲最新视频在线观看| 欧美视频国产视频| 久久一区91| 国产欧美日韩中文字幕| 成人影院免费观看| 欧美午夜电影网| 无码少妇一区二区| 日韩精品欧美成人高清一区二区| 免费一区二区三区| 久久青青视频| 亚洲天堂开心观看| 欧美国产一级片| 久久99久久99精品免视看婷婷| 日本一区不卡| 日韩精品免费观看视频| 欧美一区二区在线播放| 免费看的黄色录像| 麻豆国产精品视频| 在线免费观看一区二区三区| 日韩成人在线电影| 久久亚洲影音av资源网 | 国产精品一区二区久久国产| 久草视频在线看| 欧美在线免费视屏| 国产精品suv一区二区88| 日本不卡在线视频| 一区二区91美女张开腿让人桶| 欧美极品在线| 欧美大肥婆大肥bbbbb| 亚洲av综合色区无码一区爱av| 亚洲午夜免费电影| 亚洲天堂网一区二区| 久久免费高清| 在线精品亚洲一区二区| 欧美日韩午夜电影网| 久久久久免费精品国产| 午夜视频在线播放| 欧美综合天天夜夜久久| 成人免费精品动漫网站| 福利一区在线观看| 精品视频无码一区二区三区| 亚洲理论电影| 国产日韩在线一区| 麻豆av在线播放| 亚洲视频在线看| 国产精品乱码一区二区| 亚洲国产三级在线| 蜜桃传媒一区二区亚洲| 精品一区二区三区视频 | 日韩福利小视频| 成人亚洲一区二区一| 日韩欧美一区二区三区四区| 欧美黑粗硬大| 国产69精品久久久| 69视频在线观看| 精品sm在线观看| 亚洲国产精品无码久久久| 成人一区二区在线观看| 蜜臀av午夜一区二区三区| 99视频精品全部免费在线视频| 99国产视频在线| 久草免费在线观看| 亚洲高清久久网| 在线观看国产精品视频| 亚洲午夜在线观看视频在线| 中文字幕网站在线观看| 国产二区国产一区在线观看| 国产第一页视频| 国产精品v亚洲精品v日韩精品| 日韩视频精品| 久久久久久久久久久久久久久久久久久久 | 欧美丰满高潮xxxx喷水动漫| 天堂在线中文视频| 成人午夜大片免费观看| 国产喷水theporn| 99在线精品免费视频九九视 | 国产女主播一区二区三区| 国产一区二区色噜噜| 欧美亚洲视频在线观看| 欧美理论片在线播放| 搡老女人一区二区三区视频tv| 色网站免费观看| 欧美tk丨vk视频| 国产精品自偷自拍| 欧美亚洲高清一区| 五月婷婷色丁香| 亚洲高清在线视频| 久操视频免费在线观看| 亚洲欧洲色图综合| 国产三级黄色片| 久久久不卡影院| 91精品国产自产| 99re在线精品| 国产一级伦理片| 高清shemale亚洲人妖| 性久久久久久久久久久久久久| 蜜臀精品一区二区三区在线观看| 国产二区视频在线播放| 亚洲黄网站黄| 草草视频在线免费观看| 欧美视频日韩| 久久福利一区二区| 欧美一区不卡| 神马午夜伦理影院| 欧美在线首页| 波多野结衣 作品| 欧美一区网站| 日本成人在线不卡| 一区二区免费不卡在线| 欧美日韩视频免费在线观看| av综合网页| 91在线免费看片| 亚洲精品国产九九九| 97伦理在线四区| h视频久久久| 国内精品一区二区| 香蕉视频一区| 日韩videos| 欧美激情偷拍自拍| 亚洲天堂第一区| 欧美日韩午夜| 国产91在线免费| 天堂av在线一区| 欧美一级视频在线| 国产精品综合二区| a级一a一级在线观看| 2019国产精品| 无码人中文字幕| 亚洲乱码中文字幕| 日韩经典在线观看| 色婷婷狠狠综合| 亚洲综合五月天婷婷丁香| 欧美一区二区三区在线| 隣の若妻さん波多野结衣| 精品在线欧美视频| 秋霞午夜在线观看| 欧美激情第1页| xxxxxx欧美| 91精品视频在线免费观看| 99热这里只有精品首页| 日韩hmxxxx| 中文字幕免费一区二区| 男人日女人下面视频| 蜜桃久久久久久| 亚洲精品乱码久久久久久蜜桃欧美| 91蜜桃在线观看| 九九精品视频免费| 精品国产91久久久久久老师| 亚洲视屏在线观看| 日韩精品一区二区三区视频| 中文字幕日韩三级| 欧美大片在线观看一区| 欧美69xxxxx| 毛片精品免费在线观看| h片在线观看视频免费免费| 欧美成人精品在线| 日韩大片免费观看| 成人性生交xxxxx网站| 老汉色老汉首页av亚洲| 亚洲乱码国产乱码精品天美传媒| 狠狠综合久久av一区二区老牛| 国产精品-区区久久久狼| 国产精品一级在线| 中文字幕免费在线看线人动作大片| 一区二区三区蜜桃网| 久久午夜鲁丝片| 亚洲精品第一国产综合精品| 免费在线视频欧美| 68精品久久久久久欧美| 日韩国产一二三区| 欧美 日韩 国产在线| 国产精品a久久久久| 亚洲最大成人在线观看| 99久久伊人网影院| 男人操女人的视频网站| 91黄色免费看| 亚洲日本香蕉视频| 欧美日韩国产成人| 欧美一级免费| 日本高清不卡三区| 亚洲深夜av| 中文字幕永久免费| 亚洲视频狠狠干| 波多野结衣人妻| 国产视频综合在线| www.九色在线| 超碰97人人人人人蜜桃| 91精品秘密在线观看| 欧美日韩亚洲自拍| 久久嫩草精品久久久久| 特一级黄色大片| 精品国产亚洲在线| 日本aa在线| 亚洲最大福利视频网| 国产精品7m凸凹视频分类| 午夜免费福利在线| 国产女主播在线一区二区| 国产精品久免费的黄网站| 亚洲激情视频网| 久久男人av资源站| 精品国产一区二区三区久久久久久| 激情欧美一区二区三区| 日本少妇xxx| 92国产精品观看| 日本一级黄色大片| 亚洲国产精品一区二区三区| 91超碰免费在线| 精品国产一区二区三区免费| 亚洲一区免费| 少妇真人直播免费视频| 色94色欧美sute亚洲线路二| 国产专区在线| 国产精品久久久一区| 欧美mv日韩| 亚洲日本黄色片| 亚洲精品免费视频| 亚洲国产中文字幕在线| 久久久久久久久久久人体| 久久久久久久久久久久久久久久久久久久| 黄页免费在线观看视频| 91视频免费观看| 中文字幕永久免费视频| 久久精品亚洲国产| 日韩精品一区二区三区中文 | 亚洲欧美精品久久| 91精品国产乱| 超清av在线| 欧美国产视频在线观看| 日本sm残虐另类| 疯狂试爱三2浴室激情视频| 欧美精品一区二区三区久久久| 日本黄色免费在线| 色大师av一区二区三区| 激情综合亚洲精品| 精品无码一区二区三区电影桃花 | 欧美日本高清| 亚洲一区二区三区在线免费观看| 亚洲天堂男人| 美女被到爽高潮视频| 在线不卡一区二区| √8天堂资源地址中文在线| 欧美一区二区视频17c| 麻豆精品一区二区综合av| 特级片在线观看| 日韩精品在线播放| 二区三区精品| www一区二区www免费| 国产精品免费视频观看| 黑人精品一区二区| 国产免费一区视频观看免费| 亚洲视频一二| 国精产品一区一区| 亚洲精品一区二区三区影院| 成人自拍视频网| 免费人成自慰网站| 久久精品一区二区三区av| 99在线观看精品视频| 欧美综合激情网| 综合久久婷婷| jizz中文字幕| 亚洲国产97在线精品一区| 青青久久精品| www黄色av| 亚洲高清中文字幕|