在父线程退出时调用prctl(PR_SET_PDEATHSIG,SIGNAL),而不是父进程退出

时间:2012-05-25 20:50:51

标签: c++ multithreading fork execv

我有一个向子进程分叉的进程。如果父进程存在,则子进程不应存在。所以,我在子进程中调用:: prctl(PR_SET_PDEATHSIG,SIGKILL)来杀死它,如果父进程死掉的话。最终发生的是父线程调用pthread_exit,该线程最终成为杀死子进程的催化剂。

这是我的代码:

parent.cpp:

#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <iostream>

void* run(void* ptr) {

    std::cout << "thread:" << getpid() << ":" << std::hex << pthread_self() << ":" << std::dec << getppid() << std::endl;
    auto pid = fork();
    if ( pid != 0 ) {
        sleep(1);
    }
    else {
        char* arg = NULL;
        execv("./child", &arg);
    }
    return NULL;
}

int main() {

    std::cout << "main:" << getpid() << ":" << std::hex << pthread_self() << ":" << std::dec << getppid() << std::endl;

    pthread_t threadid;
    pthread_attr_t attr;

    ::pthread_attr_init( &attr );
    ::pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
    ::pthread_create(&threadid,&attr,run,NULL);

    sleep(6);

    return 0;
}

child.cpp:

#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <iostream>

int main() {
    std::cout << "child:" << getpid() << ":" << std::hex << pthread_self() << ":" << std::dec << getppid() << std::endl;
    ::prctl( PR_SET_PDEATHSIG, SIGKILL );
    sleep(6);


    return 0;
}

在命令行上运行以下命令:

$ ./parent

同时,运行以下命令以查找子项的状态:

$ for i in {1..10000}; do ps aux | grep child ; sleep .5; done

孩子已经不复存在了。如果您在孩子身上取出prctl电话,它就不会失效。

http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html处的prctl页面似乎描述了当父进程终止时,此调用应该调用SIGKILL,而不是父线程。当父进程死而不是父线程时,有没有办法让prctl终止子进程?

2 个答案:

答案 0 :(得分:2)

子进程终止,因为它在父线程死亡时收到PR_SET_PDEATHSIG信号。这意味着当创建它的线程死亡时它会获得一个信号。因此,如果您希望子进程依赖父进程(我假设您的意思是&#34; main&#34;函数死亡)从父进程执行的主线程中分叉。如果您在Linux prctl(2) man page查找手册页,他们会明确指出它是创建此过程的线程,将信号传递给调用(在您的情况下是子项)过程:

  

警告:&#34;父母&#34;在这种情况下被认为是   创建此过程的线程。换句话说,信号   将在该线程终止时发送(例如,通过   pthread_exit(3)),而不是在所有线程之后   父进程终止。

底线: 如果您希望它依赖于父进程的执行,则从主执行线程中分叉。简单来说,不要创建一个线程来分叉子进程,只需从主线程中分叉它。

答案 1 :(得分:-2)

你需要了解一些关于线程的事情(我的知识来自C,但这个实现似乎与我在C中所做的大部分相似)

进程是一个很重的东西,可以包含多个线程,我相信你知道。

我相信这里发生的事情:父线程被杀死,子线程也不会收到任何应该死的信号。

您需要确保当您的流程结束时,它会将其广播到它包含的所有线程,而不仅仅是父线程。

以下the LLNL tutorial on POSIX threads图表

很好地证明了这一点

enter image description here

我认为修复只是为了确保在初始化线程时调用pthread_join。

希望这有帮助!