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

use*_*199 5 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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

$ ./parent
Run Code Online (Sandbox Code Playgroud)

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

$ for i in {1..10000}; do ps aux | grep child ; sleep .5; done
Run Code Online (Sandbox Code Playgroud)

孩子去世了。如果您在child中取出prctl调用,则该调用不会失效。

http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html上的prctl页面似乎描述了当父进程死亡而不是父线程死亡时,此调用应调用SIGKILL 。当父进程(而不是父线程)死亡时,有什么方法可以使prctl杀死子进程?

Abh*_*tel 6

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

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

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