我有一个向子进程分叉的进程。如果父进程存在,则子进程不应存在。所以,我在子进程中调用:: 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终止子进程?
答案 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图表
很好地证明了这一点
我认为修复只是为了确保在初始化线程时调用pthread_join。
希望这有帮助!