<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
"); //-->

博客專(zhuān)欄

EEPW首頁(yè) > 博客 > 嵌入式Linux:如何監視子進(jìn)程

嵌入式Linux:如何監視子進(jìn)程

發(fā)布人:美男子玩編程 時(shí)間:2024-10-15 來(lái)源:工程師 發(fā)布文章

在嵌入式Linux系統中,父進(jìn)程通常需要創(chuàng )建子進(jìn)程來(lái)執行特定任務(wù),例如處理網(wǎng)絡(luò )請求、執行計算任務(wù)等。


監視子進(jìn)程的狀態(tài)不僅可以確保資源的合理利用,還能防止僵尸進(jìn)程的產(chǎn)生,從而提升系統的穩定性和性能。wait()和waitpid()是用于監視和管理子進(jìn)程的關(guān)鍵系統調用,而SIGCHLD信號則提供了一種異步通知機制,以便父進(jìn)程在子進(jìn)程狀態(tài)發(fā)生變化時(shí)采取相應的措施。

1


wait()函數

wait()系統調用用于讓父進(jìn)程等待任意一個(gè)子進(jìn)程的終止,并獲取該子進(jìn)程的終止狀態(tài)信息。


它執行以下功能:

  • 等待子進(jìn)程終止父進(jìn)程在調用wait()后會(huì )阻塞,直到其任意一個(gè)子進(jìn)程終止為止。

  • 回收子進(jìn)程資源當子進(jìn)程終止時(shí),操作系統需要回收它占用的資源,這一過(guò)程稱(chēng)為“收尸”。如果不進(jìn)行回收,子進(jìn)程會(huì )變?yōu)榻┦M(jìn)程,占用系統資源。


僵尸進(jìn)程是已經(jīng)終止,但父進(jìn)程尚未讀取其終止狀態(tài)的子進(jìn)程。通過(guò)調用wait()可以避免系統中積累僵尸進(jìn)程,影響性能和穩定性。


函數原型如下:


#include <sys/types.h>#include <sys/wait.h>pid_t wait(int *status);


參數與返回值:

  • status這是一個(gè)指向int的指針,用于存儲子進(jìn)程的退出狀態(tài)。父進(jìn)程可以通過(guò)這個(gè)狀態(tài)了解子進(jìn)程是正常退出還是被信號中止的。如果傳入NULL,則表示不關(guān)心子進(jìn)程的退出狀態(tài),僅僅是等待它終止。

  • 返回值返回已終止的子進(jìn)程的進(jìn)程ID;如果調用時(shí)沒(méi)有子進(jìn)程存在,wait()返回-1,并將errno設為ECHILD表示沒(méi)有子進(jìn)程可等待。


函數行為:

  • 阻塞等待wait()會(huì )阻塞調用進(jìn)程,直到任意一個(gè)子進(jìn)程終止。如果所有子進(jìn)程都還在運行,wait()將持續阻塞。

  • 資源回收當子進(jìn)程終止時(shí),wait()除了獲取子進(jìn)程的終止狀態(tài),還會(huì )回收子進(jìn)程的資源,避免產(chǎn)生僵尸進(jìn)程。

  • 處理已終止的子進(jìn)程如果wait()調用時(shí)有子進(jìn)程已終止,函數將立即返回,而不會(huì )阻塞。


狀態(tài)檢查,使用宏可以檢查和處理status參數中存儲的子進(jìn)程終止狀態(tài):

  • WIFEXITED(status)如果子進(jìn)程是通過(guò)exit()或_exit()正常終止的,則返回true。

  • WEXITSTATUS(status)當WIFEXITED(status)為true時(shí),可以通過(guò)該宏獲取子進(jìn)程的退出狀態(tài),通常是子進(jìn)程在調用exit()或_exit()時(shí)的退出碼。

  • WIFSIGNALED(status)如果子進(jìn)程因接收到某個(gè)信號而異常終止,則返回true。

  • WTERMSIG(status)當WIFSIGNALED(status)為true時(shí),可以通過(guò)該宏獲取導致子進(jìn)程終止的信號編號。

  • WIFSTOPPED(status)如果子進(jìn)程處于暫停狀態(tài),則返回true。

  • WSTOPSIG(status)當WIFSTOPPED(status)為true時(shí),可以獲取導致子進(jìn)程暫停的信號編號。

  • WCOREDUMP(status)如果子進(jìn)程終止時(shí)生成了核心轉儲文件,則返回true。


以下示例展示了如何使用wait()函數來(lái)監視子進(jìn)程的終止狀態(tài)。


#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h> int main() {    pid_t pid = fork();  // 創(chuàng  )建子進(jìn)程     if (pid == -1) {        // fork()失敗        perror("fork failed");        exit(EXIT_FAILURE);    } else if (pid == 0) {        // 子進(jìn)程執行代碼        printf("Child process running (PID: %d)...n", getpid());        sleep(2);  // 模擬子進(jìn)程的執行        exit(42);  // 正常退出,并返回狀態(tài)碼42    } else {        // 父進(jìn)程執行代碼        int status;        pid_t child_pid = wait(&status);  // 等待任一子進(jìn)程終止         if (child_pid > 0) {            // 子進(jìn)程終止后的處理            if (WIFEXITED(status)) {                printf("Child process %d terminated with status: %dn", child_pid, WEXITSTATUS(status));            } else if (WIFSIGNALED(status)) {                printf("Child process %d was terminated by signal: %dn", child_pid, WTERMSIG(status));            }        } else {            perror("wait failed");        }    }     return 0;}


在這段代碼中,父進(jìn)程創(chuàng )建了一個(gè)子進(jìn)程并等待其終止,同時(shí)通過(guò)status宏獲取子進(jìn)程的退出狀態(tài)。


wait()函數的局限性:

  • 無(wú)法指定特定子進(jìn)程wait()無(wú)法讓父進(jìn)程選擇等待某個(gè)特定的子進(jìn)程,它只能按順序等待下一個(gè)終止的子進(jìn)程。如果父進(jìn)程同時(shí)擁有多個(gè)子進(jìn)程,wait()將隨機處理任意一個(gè)子進(jìn)程的終止。

  • 阻塞等待wait()始終是阻塞的,直到有子進(jìn)程終止為止。如果父進(jìn)程需要繼續處理其他任務(wù),則wait()的阻塞可能導致父進(jìn)程效率低下。


2


waitpid()函數

waitpid()函數提供了更多的控制選項,使得父進(jìn)程可以選擇性地等待某個(gè)特定子進(jìn)程,或進(jìn)行非阻塞的等待。


函數原型如下:


#include <sys/types.h>#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);


參數:

  • pid指定需要等待的子進(jìn)程:

    • > 0:等待指定PID的子進(jìn)程。

    • = 0:等待與調用進(jìn)程同一進(jìn)程組的任意子進(jìn)程。

    • < -1:等待進(jìn)程組ID等于pid絕對值的所有子進(jìn)程。

    • = -1:等待任意子進(jìn)程,與wait()等價(jià)。

  • status與wait()的status參數相同。

  • options可以設置為0或包含以下標志:

    • WNOHANG非阻塞模式。如果沒(méi)有子進(jìn)程終止,立即返回0。

    • WUNTRACED返回因信號停止的子進(jìn)程的狀態(tài)。

    • WCONTINUED返回收到SIGCONT信號后恢復運行的子進(jìn)程的狀態(tài)。


返回值:

  • 成功時(shí),返回已終止或狀態(tài)已改變的子進(jìn)程的PID。

  • 如果沒(méi)有符合條件的子進(jìn)程,且設置了WNOHANG選項,返回0。

  • 失敗時(shí)返回-1,并設置errno。


waitpid()與wait()的區別:

  • 等待特定子進(jìn)程waitpid()允許父進(jìn)程通過(guò)pid參數指定特定的子進(jìn)程,而wait()只能等待任意子進(jìn)程。

  • 非阻塞模式waitpid()支持非阻塞模式(通過(guò)WNOHANG),使父進(jìn)程可以立即返回,而不必等待子進(jìn)程終止。

  • 支持更多狀態(tài)監控waitpid()可以監視子進(jìn)程暫停(WUNTRACED)或恢復運行(WCONTINUED)的狀態(tài),而wait()無(wú)法做到這一點(diǎn)。


示例代碼:


#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h> int main() {    pid_t pid = fork();  // 創(chuàng  )建子進(jìn)程     if (pid == -1) {        // fork()失敗        perror("fork failed");        exit(EXIT_FAILURE);    } else if (pid == 0) {        // 子進(jìn)程執行代碼        printf("Child process running (PID: %d)...n", getpid());        sleep(2);  // 模擬子進(jìn)程工作        exit(42);  // 正常退出,返回狀態(tài)碼42    } else {        // 父進(jìn)程執行代碼        int status;        pid_t child_pid;         // 非阻塞等待子進(jìn)程        do {            child_pid = waitpid(pid, &status, WNOHANG);  // 非阻塞模式            if (child_pid == 0) {                printf("No child process terminated yet. Doing other work...n");                sleep(1);  // 模擬其他工作            } else if (child_pid > 0) {                if (WIFEXITED(status)) {                    printf("Child process %d terminated with status: %dn", child_pid, WEXITSTATUS(status));                } else if (WIFSIGNALED(status)) {                    printf("Child process %d was terminated by signal: %dn", child_pid, WTERMSIG(status));                }            } else {                perror("waitpid failed");                exit(EXIT_FAILURE);            }        } while (child_pid == 0);         printf("Parent process continues...n");    }     return 0;}



在這個(gè)示例中,父進(jìn)程可以繼續處理其他任務(wù),而不必一直阻塞等待子進(jìn)程的終止。waitpid()的非阻塞模式使得程序更為靈活和高效。 


3


SIGCHLD信號

SIGCHLD是父進(jìn)程在子進(jìn)程狀態(tài)發(fā)生變化(如終止或暫停)時(shí)收到的信號。通過(guò)捕獲SIGCHLD信號,父進(jìn)程可以實(shí)時(shí)地檢測到子進(jìn)程的狀態(tài)變化,并采取相應的行動(dòng)(例如回收資源)。


在POSIX標準下,sigaction()系統調用被廣泛用于設置信號處理程序。相比于傳統的signal()函數,sigaction()提供了更多的選項和更好的控制。


示例代碼:


#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h> void sigchld_handler(int signum) {    int status;    pid_t pid;     // 循環(huán)調用waitpid,以確保處理多個(gè)已終止的子進(jìn)程    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {        if (WIFEXITED(status)) {            printf("Child process %d terminated with status: %dn", pid, WEXITSTATUS(status));        } else if (WIFSIGNALED(status)) {            printf("Child process %d was terminated by signal: %dn", pid, WTERMSIG(status));        }    }} int main() {    struct sigaction sa;    sa.sa_handler = sigchld_handler;  // 指定信號處理函數    sigemptyset(&sa.sa_mask);  // 清空阻塞信號集    sa.sa_flags = SA_RESTART;  // 自動(dòng)重啟被中斷的系統調用    sigaction(SIGCHLD, &sa, NULL);  // 安裝信號處理程序     for (int i = 0; i < 3; i++) {        pid_t pid = fork();  // 創(chuàng  )建多個(gè)子進(jìn)程        if (pid == 0) {            // 子進(jìn)程代碼            printf("Child process %d running...n", getpid());            sleep(2);            exit(42);        }    }     // 父進(jìn)程的其他工作    while (1) {        printf("Parent process working...n");        sleep(1);    }     return 0;}


使用sigaction()的優(yōu)點(diǎn):

  • 自動(dòng)重啟通過(guò)設置SA_RESTART標志,能夠在信號處理完成后自動(dòng)重啟被中斷的系統調用(如read()、write())。

  • 可靠的信號處理sigaction()避免了傳統signal()函數的缺陷,確保了信號處理的可靠性和可移植性。


SIGCHLD信號的常見(jiàn)問(wèn)題與解決方案:

  • 丟失信號在同時(shí)終止多個(gè)子進(jìn)程時(shí),可能會(huì )丟失一些SIGCHLD信號。為解決這一問(wèn)題,可以在信號處理程序中循環(huán)調用waitpid(),直到?jīng)]有子進(jìn)程終止為止。

  • 阻塞的系統調用信號處理可能會(huì )中斷一些阻塞的系統調用(如read()或sleep()),導致它們返回錯誤。通過(guò)使用sigaction()的SA_RESTART標志可以自動(dòng)重啟被中斷的調用。


通過(guò)以上內容,開(kāi)發(fā)者可以根據實(shí)際需求選擇合適的方法來(lái)監視和管理子進(jìn)程,確保程序運行的穩定性和資源的有效利用。


  • 如果只需等待任意一個(gè)子進(jìn)程終止且不關(guān)心特定子進(jìn)程,使用wait()是最簡(jiǎn)單的選擇。

  • 如果需要非阻塞地等待特定子進(jìn)程或需要獲取更多子進(jìn)程狀態(tài)信息,waitpid()則更為靈活。

  • 在處理多個(gè)子進(jìn)程時(shí),捕獲SIGCHLD信號可以讓父進(jìn)程更加實(shí)時(shí)地處理子進(jìn)程的終止,并在不中斷父進(jìn)程正常操作的情況下回收子進(jìn)程資源。


無(wú)論是使用wait()、waitpid()還是SIGCHLD信號處理,確保及時(shí)回收子進(jìn)程的資源是避免僵尸進(jìn)程的關(guān)鍵。

*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。



關(guān)鍵詞: 嵌入式 Linux

相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>