Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用SIGCHLD处理僵尸_C_Unix_Operating System_Signals - Fatal编程技术网

用SIGCHLD处理僵尸

用SIGCHLD处理僵尸,c,unix,operating-system,signals,C,Unix,Operating System,Signals,在我的程序中,我正在收听传入的信号以避免僵尸 代码: void myhandler(int signo) { printf("test"); int status; pid_t pid; while((pid = waitpid(-1, &status, WNOHANG)) > 0) ++count; } int main(int argc, char const *argv[]) { struct sigacti

在我的程序中,我正在收听传入的信号以避免僵尸

代码:

void myhandler(int signo)
{   
    printf("test");
    int status;
    pid_t pid;

    while((pid = waitpid(-1, &status, WNOHANG)) > 0)
        ++count;
}

int main(int argc, char const *argv[])
{

    struct sigaction sigchld_action;
    memset(&sigchld_action,0,sizeof(sigchld_action));
    sigchld_action.sa_handler = &myhandler;
    sigaction(SIGCHLD,&sigchld_action,NULL);

    if(fork() == 0){
        exit(0);
    }
    if(fork()==0){
        exit(0);
    }
    if(fork()==0){
        exit(0);
    }


    while(wait(NULL) > 0)
    ++count;

    return 0;
}
问题是,分叉子对象的数量和printf(“test”)的输出数量有时不匹配。分叉儿童的数量大于数字printf(“测试”)

这个代码段是否保证不会有僵尸?如果是,如何做到这一点??它没有打印正确的“测试”编号。waitpid()是否会在一段时间内多次清除死去的孩子

当这个信号处理程序调用时,会发生什么,同时另一个孩子可能会死亡。默认情况下,信号将被阻止。(当处理程序运行时,另一个子项可能死亡)。waitpid是否清除在信号处理程序运行时发送其信号的进程


而且,计数器是不相等的。(静态volatile int)或我尝试了原子整数。

发生了两件不同的事情:

  • printf
    不是异步信号安全的,所以不应该从信号处理程序调用它。将其替换为
    write
  • 您在信号处理程序中只增加一次计数。如果您想知道有多少进程死亡,您需要在
    while
    循环中增加它
  • 请尝试以下代码:

    void handler(int signo)
    {   
        int status;
        pid_t pid;
        while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
            write(1, "test", 4); /* technically this may result in a partial write and you should loop it, but in practice I think this'll be fine for this example */
            ++count;
        }
    }
    

    有了这些代码,您可能就没有僵尸了,并且拥有正确数量的
    test
    s和正确的
    count
    值。但是,还有一个竞争条件:如果在最后一次调用
    waitpid
    和信号处理程序结束之间,另一个子进程死亡,那么将不会收到
    SIGCHLD
    ,因此它将是一个僵尸,直到它死后的一个子进程。这种边缘情况的解决方案要复杂得多,这取决于应用程序其余部分的结构。

    在信号处理程序中不能安全地使用stdio函数,例如
    printf()
    ,顺便说一句。@Shawn是的,我知道,但如果使用原子计数器,结果是一样的。他只是意味着相同类型的挂起信号不排队,它们被丢弃了。此外,信号处理程序在处理程序的持续时间内屏蔽信号(除非您明确阻止它这样做)。所以他们到了,但他及时得到了处理。你不会以这种方式收获所有的孩子——僵尸会出现。事实上,我上一句话是错误的,可能所有的孩子都会在while循环中收获。即使处理程序只被调用一次。在这里,检查调用处理程序的次数不是有效的指标。您的代码通过这种方式毕竟是安全的,很抱歉在一些statements@Root2A我就是这么想的,是的。若并没有更多的子进程可以收获,它将退出处理程序,但当SIGCHLD再次出现时,您只需再次输入处理程序。结果相同,在5个进程中,计数在2-3-5之间变化。但是我在父级的末尾添加了一个无限循环,以避免终止父级,然后我运行ps,我没有看到任何僵尸。如果计数小于进程数,怎么就没有僵尸?@Root2A你能编辑你的问题,使之包含完整的程序,而不仅仅是一个信号处理程序吗?然后可能会更清楚发生了什么。@Root2A两件有趣的事情:1<代码>处理程序vs.
    myhandler
    。2.如果希望信号处理程序执行等待,那么为什么在
    main
    中有
    wait
    ?@Root2A从来没有孤立进程。当一个进程在其子进程尚未收获的情况下死亡时,子进程将被收养(通常通过
    init
    )。您没有看到僵尸,因为
    init
    在父级退出后正在捕获它们。@Root2A您在
    main
    末尾使用
    while(wait(NULL)>0)
    的最新版本将永远不会在其所有子级退出之前退出。(当然,它仍然可能是
    kill-9
    d或其他东西。)