精品欧美一区二区三区在线观看 _久久久久国色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在线观看地址| 欧美激情1区2区| 欧美精品xxxxbbbb| 欧美亚洲黄色片| 飘雪影视在线观看免费观看 | 99免费精品在线| 国产91色在线免费| 男人与禽猛交狂配| 久久av综合| 国产视频网站一区二区三区| 肉肉av福利一精品导航| www.亚洲一区| 中文字幕免费在线播放| 国产原创一区| 欧美日韩精品在线观看| 一区不卡视频| 亚洲av成人精品毛片| 激情综合色综合久久| 18性欧美xxxⅹ性满足| 成人在线观看免费完整| 九九视频精品全部免费播放| 欧美成人性战久久| 午夜免费看视频| 亚洲精品永久免费视频| 玉米视频成人免费看| 性欧美.com| 天天躁日日躁狠狠躁喷水| 久久99精品视频| 国产成人精品最新| 日韩欧美三级视频| 激情成人亚洲| 欧美大肥婆大肥bbbbb| 波多野结衣家庭教师在线观看 | 91精品国产乱码| 任你操这里只有精品| 国产理论电影在线| 亚洲蜜臀av乱码久久精品| 日韩欧美99| 青青青草原在线| 99re这里只有精品首页| 国产不卡一区二区三区在线观看| 中文字幕一区二区三区免费看| 日韩视频精品在线观看| 欧美激情va永久在线播放| 小早川怜子一区二区的演员表| 不卡日本视频| 亚洲欧美中文字幕| 久久无码人妻精品一区二区三区 | 97超碰免费在线| 亚洲中国最大av网站| 日韩a级黄色片| 色呦呦在线资源| 一区二区高清在线| 九九久久九九久久| 性直播体位视频在线观看| 亚洲免费观看高清| 狠狠精品干练久久久无码中文字幕 | 久国产精品韩国三级视频| 国产精品偷伦一区二区| 中文字幕人妻精品一区| 老司机精品视频在线| 国产美女久久精品| 一级二级三级视频| 久久99精品国产.久久久久| 国产乱肥老妇国产一区二| 中文字幕欧美人妻精品| 久久99久久精品欧美| 91精品国产综合久久男男 | 久久精品波多野结衣| 欧美日韩国产一区精品一区| 欧美精品videossex88| 香蕉视频一区二区| 男人的天堂亚洲在线| 日韩免费观看高清| 亚洲天堂视频网| 国产一区二区精品久久99| 99在线国产| 污污网站免费在线观看| 久久久99精品免费观看| 亚洲欧洲日韩精品| 在线观看h网| 午夜精品爽啪视频| av在线无限看| 精品中文字幕一区二区三区| 精品电影一区二区| 亚洲天堂久久新| 91中文字幕精品永久在线| 欧美人与性动交a欧美精品| 日韩毛片在线播放| 蜜臀av一区二区三区| 91精品国产高清久久久久久91裸体| 亚洲男女在线观看| 一区二区久久精品66国产精品| 青草国产精品久久久久久| 91探花福利精品国产自产在线| 亚洲成人77777| 久久久影视传媒| 男人的天堂成人| 男人av在线播放| 欧美久久久一区| 亚洲中文字幕一区| 国产精品久久久久蜜臀| 午夜精品一区二区三区在线视频| 不卡av电影在线| 国产成人在线看| 日韩亚洲不卡在线| 国产免费拔擦拔擦8x高清在线人| 欧美日韩黄色一区二区| 菠萝菠萝蜜网站| 欧美久久久久| 国产精品爽黄69| 无码精品黑人一区二区三区 | 欧美日韩亚洲在线 | 欧美理论在线播放| 欧美激情网友自拍| 最近中文字幕在线观看| 粉嫩av亚洲一区二区图片| 台湾成人av| 九色porny自拍视频在线播放 | 99九九99九九九99九他书对| 琪琪久久久久日韩精品 | 欧美性猛交xxxxx少妇| 新67194成人永久网站| 91久久极品少妇xxxxⅹ软件| 国产精品一区二区三区四区色| 亚洲一区二区五区| 亚洲色图偷拍视频| 欧美色女视频| 日本免费久久高清视频| 秋霞视频一区二区| 一区二区三区中文免费| 亚洲一区日韩精品| 欧美手机视频| 国产成人一区二区三区小说| 欧美熟女一区二区| 亚洲一区二区欧美| 成年人看片网站| 亚洲一级淫片| 成人福利在线视频| 色欧美激情视频在线| 精品成人国产在线观看男人呻吟| 美女日批在线观看| 欧美精品播放| 成人欧美一区二区| 日本中文字幕中出在线| 日韩免费观看高清完整版在线观看| 国产精品69久久久久孕妇欧美| 天堂一区二区在线免费观看| 欧美精品二区三区四区免费看视频| brazzers在线观看| 欧美精品一区男女天堂| 国产精品9191| 成人国产视频在线观看| 欧美乱大交xxxxx潮喷l头像| 成人在线超碰| 91av在线播放| 午夜性色福利视频| 日本高清不卡aⅴ免费网站| 白白色免费视频| 青青草国产精品97视觉盛宴| 亚洲成色www久久网站| 992tv国产精品成人影院| 色yeye香蕉凹凸一区二区av| 夜夜狠狠擅视频| 亚洲视频免费在线观看| 日本55丰满熟妇厨房伦| 亚洲国产影院| 日本精品一区二区| 成人国产精品入口免费视频| 爱福利视频一区| 亚洲国产福利视频| 天天综合天天做天天综合| 亚洲自拍偷拍一区二区| 免费观看30秒视频久久| 懂色av粉嫩av蜜臀av| 99精品国产一区二区三区2021| 97视频免费在线观看| 日本v片在线免费观看| 欧美综合在线视频| 国产精品丝袜一区二区| 成人激情视频网站| 一区二区三区免费播放| 欧美成人中文| 欧美成人综合一区| 成人在线中文| 久久久久国色av免费观看性色| 日本精品专区| 91精品久久久久久久99蜜桃| 日本亚洲色大成网站www久久| 久久久噜噜噜久久中文字幕色伊伊| 网站一区二区三区| 激情文学一区| 日本不卡一区二区三区在线观看 | 国产精品欧美久久| 巨胸喷奶水www久久久免费动漫| 久久天天躁夜夜躁狠狠躁2022| 韩国av免费在线观看| 亚洲美女网站| 亚洲国产成人91精品| 在线视频一区二区三区四区| 国产精品家庭影院| 免费成人蒂法网站| 国内精品免费**视频| 精品视频免费在线播放| 91免费精品| 欧美日韩一区二区三区在线视频| 精品一区二区三区亚洲| 国产999在线观看| 欧美1—12sexvideos| 亚洲丝袜在线视频| 欧美在线精品一区二区三区| 91麻豆精品国产91久久久久久久久 | www.激情五月| 欧美在线视频不卡| 日韩av电影网址| 亚洲欧美日韩一区二区 | 成久久久网站| 黑人巨大精品欧美一区二区小视频| 亚洲精品乱码日韩| 欧美性视频精品| 免费看电影在线| 久久精品影视伊人网| 国产一级在线观看| 日韩精品久久久久久福利| www.污视频| 欧美精品久久久久久久多人混战| 秋霞av一区二区三区| 午夜精品影院在线观看| 国产黄色片在线免费观看| 中文子幕无线码一区tr| 无码人妻精品一区二区三应用大全 | 偷拍欧美精品| 神马影院一区二区| 九九免费精品视频在线观看| 精品无人区一区二区三区| 高清日韩中文字幕| 97超碰人人模人人爽人人看| 精品国产亚洲一区二区三区大结局 | 亚洲人成电影网| 无码国产精品一区二区色情男同 | 都市激情一区| 亚洲欧美制服另类日韩| 香港一级纯黄大片| 日韩电影中文 亚洲精品乱码| 少妇高潮一区二区三区69| 精品久久免费看| 性做久久久久久久久久| 欧美本精品男人aⅴ天堂| www.日韩高清| 精品国产sm最大网站免费看| 亚洲精品一区二区口爆| 精品成人免费观看| 色呦呦中文字幕| 亚洲经典中文字幕| 日本大臀精品| 中文字幕九色91在线| 欧美精品电影| 久久精品91久久香蕉加勒比| 成人在线网址| 欧美激情亚洲视频| 深夜成人在线| 国产精品69久久| 国产精品亲子伦av一区二区三区| 国产精品视频专区| 99国内精品久久久久| 69174成人网| 欧美巨大xxxx| 日韩精品欧美一区二区三区| 水蜜桃久久夜色精品一区| 亚洲成人动漫在线| 亚洲午夜伦理| 麻豆av免费在线| 美女mm1313爽爽久久久蜜臀| 日韩欧美色视频| 99久久综合国产精品| 久久精品无码一区| 综合久久久久综合| 日本最新中文字幕| 欧美在线看片a免费观看| 国产免费福利视频| 亚洲精品福利免费在线观看| 九一在线视频| 萌白酱国产一区二区| 日韩精品美女| 成人久久久久爱| 午夜精品影视国产一区在线麻豆| 四虎永久国产精品| 欧美特黄一区| 日韩一级片播放| 国产精品性做久久久久久| 91久久免费视频| 夜夜嗨av一区二区三区| 草久视频在线观看| 3d动漫精品啪啪一区二区竹菊| 天天射,天天干| 久久精品精品电影网| 日本不卡1234视频| 91免费福利视频| 伊人久久大香线蕉| 日韩人妻一区二区三区蜜桃视频| 六月丁香综合| 精品国产aⅴ一区二区三区东京热 久久久久99人妻一区二区三区 | 精品视频一二区| 久久99精品视频一区97| 欧美大片高清| 国产日韩久久| 天天射综合网视频| 国产极品美女高潮无套久久久| 韩国v欧美v亚洲v日本v| 精品人妻少妇嫩草av无码| 亚洲天堂中文字幕| 亚洲欧美日韩激情| 亚洲精品一区二区三区四区高清| 欧美69xxx| 国产精品99久久久久久白浆小说| **爰片久久毛片| 影音先锋欧美在线| 日韩激情一二三区| 成人手机在线免费视频| 亚洲综合在线观看视频| 国产又粗又大又爽视频| 亚洲天堂av网| 日韩激情电影| 国产在线精品日韩| 国产尤物精品| 手机看片国产精品| 18涩涩午夜精品.www| 国内av在线播放| 亚洲欧美制服另类日韩| 在线视频超级| 九九99久久| 99av国产精品欲麻豆| 涩视频在线观看| 一区二区三区资源| 99久久精品国产色欲| 久久精品视频在线| 成人日韩视频| 美国av在线播放| 精品一区二区三区免费毛片爱| 在线观看免费小视频| 一本久久a久久免费精品不卡| 天天舔天天干天天操| 97国产精品视频| 国内精品免费| 男人添女人下部高潮视频在观看| 国产成人精品免费在线| www.超碰在线观看| 日韩一区二区免费在线电影| 含羞草www国产在线视频| 91久久久久久久久久久久久| 99久久国产综合精品成人影院| 色悠悠久久综合网| 国产精品沙发午睡系列990531| 这里只有久久精品视频| 中文字幕在线精品| 国产精品18| 久久久久久久久久伊人| 国产69精品一区二区亚洲孕妇| 久久综合色综合| 日韩大片在线观看视频| 一区二区电影免费观看| 欧洲精品亚洲精品| 久久97超碰国产精品超碰| 卡通动漫亚洲综合| 精品福利一二区| 亚洲天堂导航| 亚洲欧美日韩精品在线| 国产综合成人久久大片91| 青草草在线视频| 亚洲精品大尺度| 精品视频一区二区三区四区五区| 在线视频不卡一区二区三区| 国产精品一级二级三级| 91精品国产乱码在线观看| 国产亚洲欧洲在线| 国产精品一区二区三区av| 精品国偷自产一区二区三区| 91麻豆swag| 国产精品自偷自拍| 777午夜精品福利在线观看| 欧美激情在线精品一区二区三区| 天堂av2020| 偷拍亚洲欧洲综合| 亚洲搞黄视频| 好看的日韩精品| 久久精品国产精品亚洲综合| 免费在线视频一区二区| 亚洲欧美国产日韩中文字幕| 深夜福利亚洲| 国产一区二区三区小说| 国产欧美精品在线观看| 精品二区在线观看| 日韩av片免费在线观看| 一区二区在线| 美女久久久久久久久久| 日韩亚洲欧美综合| 国产另类xxxxhd高清| 国产在线视频综合| 国产午夜三级一区二区三| 国产ts变态重口人妖hd|