簡體   English   中英

將等待和waitpid阻止SIGCHLD並在Linux返回時取消阻止嗎?

[英]Will wait and waitpid block SIGCHLD and unblock it when they return in Linux?

這是我的代碼來檢查這個:

void handler(int n) {
    printf("handler %d\n", n);
    int status;
    if (wait(&status) < 0)
        printf("%s\n", strerror(errno));
}

int main() {
    struct sigaction sig;
    sigemptyset(&sig.sa_mask);
    sig.sa_handler = handler;
    sig.sa_flags = 0;
    sig.sa_restorer = NULL;
    struct sigaction sigold;
    sigaction(SIGCHLD, &sig, &sigold);
    pid_t pid;
    int status;
    printf("before fork\n");
    if ((pid = fork()) == 0) {
        _exit(127);
    } else if (pid > 0) {
        printf("before waitpid\n");
        if (waitpid(pid, &status, 0) < 0)
            printf("%s\n", strerror(errno));
        printf("after waitpid\n");
    }
    printf("after fork\n");
    return 0;
}

輸出是:

在前叉

在waitpid之前

處理程序17

沒有孩子的過程

在waitpid之后

叉后

因此,我認為waitpid將阻止SIGCHLD並等待子進程終止,一旦子進程終止,它將執行某些操作並在返回之前解鎖SIGCHLD,這就是為什么我們看到“No child processes”錯誤並且“after waitpid”之后“處理程序17” ,我是對的? 如果不是,真相是什么? 如何解釋輸出序列? 是否有針對Linux的規范或類似的東西來檢查?

進程的退出信息只能收集一次。 您的輸出顯示在代碼處於waitpid()調用的信號處理程序,但處理程序調用wait()並收集子項的信息(在沒有報告的情況下丟棄)。 然后當你回到waitpid() ,已經收集了子退出狀態,因此沒有任何東西可供waitpid()報告,因此“無子進程”錯誤。

這是您的計划的改編。 它通過在信號處理函數中使用printf()來濫用它,但它似乎工作,盡管如此,在運行macOS Sierra 10.12.4(使用GCC 7.1.0編譯)的Mac上進行測試。

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

static void handler(int n)
{
    printf("handler %d\n", n);
    int status;
    int corpse;
    if ((corpse = wait(&status)) < 0)
        printf("%s: %s\n", __func__, strerror(errno));
    else
        printf("%s: child %d exited with status 0x%.4X\n", __func__, corpse, status);
}

int main(void)
{
    struct sigaction sig = { 0 };
    sigemptyset(&sig.sa_mask);
    sig.sa_handler = handler;
    sig.sa_flags = 0;
    sigaction(SIGCHLD, &sig, NULL);
    pid_t pid;
    printf("before fork\n");
    if ((pid = fork()) == 0)
    {
        _exit(127);
    }
    else if (pid > 0)
    {
        printf("before waitpid\n");
        int status;
        int corpse;
        while ((corpse = waitpid(pid, &status, 0)) > 0 || errno == EINTR)
        {
            if (corpse < 0)
                printf("loop: %s\n", strerror(errno));
            else
                printf("%s: child %d exited with status 0x%.4X\n", __func__, corpse, status);
        }
        if (corpse < 0)
            printf("%s: %s\n", __func__, strerror(errno));
        printf("after waitpid loop\n");
    }
    printf("after fork\n");
    return 0;
}

樣本輸出:

before fork
before waitpid
handler 20
handler: child 29481 exited with status 0x7F00
loop: Interrupted system call
main: No child processes
after waitpid loop
after fork

狀態值0x7F00是_exit(127)的正常編碼。 來自Linux的macOS的信號編號不同; 這完全是允許的。


要獲得在Linux上編譯的代碼(用於測試的Centos 7和Ubuntu 16.04 LTS),使用命令行分別使用GCC 4.8.5(幾乎是antediluvian - 當前版本是GCC 7.1.0)和5.4.0:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -Wold-style-definition sg59.c -o sg59
$

我在第一個標頭之前添加了#define _XOPEN_SOURCE 800 ,並使用了:

struct sigaction sig;
memset(&sig, '\0', sizeof(sig));

使用GCC 4.8.5初始化結構。 那種shenanigan偶爾是避免編譯器警告的痛苦必要。 我注意到雖然#define是暴露POSIX符號所必需的,但GCC 5.4.0接受了初始化程序( struct sigaction sig = { 0 }; )而沒有任何問題。

當我運行該程序時,我得到的報告非常類似於cong報告的評論

before fork
before waitpid
handler 17
handler: No child processes
main: child 101681 exited with status 0x7F00
main: No child processes
after waitpid loop
after fork

確實很奇怪,在Linux上,進程發送了一個SIGCHLD信號,但wait()不能在信號處理程序中等待它。 這至少是違反直覺的。

我們可以討論waitpid()的第一個參數是pid而不是0 waitpid() ; 因為第一次從子節點收集信息,所以在循環的第二次迭代中錯誤是不可避免的。 在實踐中,這並不重要。 一般來說,最好使用waitpid(0, &status, WNOHANG)或其附近 - 根據上下文, 0而不是WNOHANG可能會更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM