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

prctl(PR_SET_PDEATHSIG, SIGNAL) is called on parent thread exit, not parent process exit

本文关键字:退出 调用 进程 PR PDEATHSIG prctl SET 线程 SIGNAL      更新时间:2023-10-16

我有一个分叉到子进程的进程。如果父进程存在,则子进程不应存在。

因此,我在子进程中调用::prctl(PR_SET_PDEATHSIG, SIGKILL),如果父进程死亡,则将其杀死。

最终发生的是父线程调用pthread_exit,该线程最终成为杀死子进程的催化剂。

这是我的代码:

家长.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;
}

儿童.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 呼叫,它不会失效。

prctl 手册页似乎描述了此调用应在父进程(而不是父线程)死亡时调用SIGKILL

有没有办法让 prctl 在父进程而不是父线程死亡时杀死孩子?

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

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

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

相关文章: