C++ fork()未按预期工作
我正在尝试创建一个程序,它产生两个进程——第一个进程监视第二个进程,如果它被杀死,则重新启动它。(想法是杀死第二个进程的唯一方法是先杀死第一个进程。)下面我有一些代码无法实现我的目标C++ fork()未按预期工作,c++,linux,process,fork,C++,Linux,Process,Fork,我正在尝试创建一个程序,它产生两个进程——第一个进程监视第二个进程,如果它被杀死,则重新启动它。(想法是杀死第二个进程的唯一方法是先杀死第一个进程。)下面我有一些代码无法实现我的目标 #include <cstdio> #include <unistd.h> #include <thread> #include <chrono> #include <signal.h> #include <cerrno> void make
#include <cstdio>
#include <unistd.h>
#include <thread>
#include <chrono>
#include <signal.h>
#include <cerrno>
void makeSiblings();
void run_ping() {
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(2));
puts("Ping.");
}
}
void run_monitor(pid_t sibling) {
while (kill(sibling, 0) != -1 and errno != ESRCH) {
printf("%d still exists.\n", sibling);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
makeSiblings();
}
void makeSiblings() {
pid_t pid1, pid2;
if ((pid1 = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid1 == 0) {
setsid();
run_ping();
}
if ((pid2 = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid2 == 0) {
setsid();
run_monitor(pid1);
}
}
int main() {
makeSiblings();
}
#包括
#包括
#包括
#包括
#包括
#包括
void makesides();
作废run_ping(){
while(true){
std::this_thread::sleep_for(std::chrono::seconds(2));
放(Ping);;
}
}
无效运行监视器(pid同级){
while(kill(兄弟,0)!=1,errno!=ESRCH){
printf(“%d仍然存在。\n”,同级);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
使兄弟姐妹();
}
void makesides(){
pid_t pid1,pid2;
if((pid1=fork())=-1){
佩罗尔(“福克”);
退出(退出失败);
}
如果(pid1==0){
setsid();
run_ping();
}
if((pid2=fork())=-1){
佩罗尔(“福克”);
退出(退出失败);
}
如果(pid2==0){
setsid();
运行监视程序(pid1);
}
}
int main(){
使兄弟姐妹();
}
当运行此代码时,它会输出Ping.
,例如,7812仍然存在。
每两秒和一秒分别输出一次,如预期的那样。然而,当我从另一个终端杀死7812
时,“Ping”过程扩散到了一个荒谬的程度——我似乎是在用叉子轰炸自己,只有通过垃圾邮件killall
我才能恢复
我似乎没有理解关于
fork()
,或者关于setsid()
的一些微妙之处。请给我一两个指针。是的,你是。。。您的函数调用fork()
两次,然后两个子函数最终将递归调用makesiblines()
当调用run\u ping()
的第一个子项完成时,它实际上并没有完成,但它将调用run\u monitor()
。然后它将调用makesibbins()
并重复,直到它爆炸
解决方案是在运行ping()之后添加一个exit()
调用:
但是现在,您可以使用
wait()
而不是kill(pid,0)
,因为ping()
进程应该是监视器进程的子进程。在makeSibling函数中,在第二个if块的末尾,添加一个出口(0);或者别的什么。因为你实际上是在用叉子轰炸。
在使用fork时,大多数时候都必须考虑这个出口
。。。int kill(pid_t pid,int sig)。。。如果sig为0(零信号),
执行了错误检查,但没有实际发送信号。空值
信号可用于检查pid的有效性
资料来源:
一方面,您实际上是在创建过程而没有杀死它们
P>另一方面,如果你从另一个终端发送的信号不是杀死,而是只破坏无限循环,第一个兄弟也会执行第二个叉。这显然是C++,所以我删除了“C”标签。C++,是的,但是问题是C程序员应该解决的问题——我在C++中写的唯一原因是利用SyePyFoE()函数。尽管如此,我还是推迟了。您应该测试
setsid
的故障。您应该使用调试器。不要忘了在fork
-ing之前刷新流。尝试strace
你的程序。监视器应该是被监视程序的父进程。您不能禁止进程被SIGKILL
杀死,我认为删除C标记是一个错误..很好!另一个解决方案是使用if-then-elseinstead@malarres:是的,但是我假设OP程序可能更复杂,并且在makesiblines()
之后的main()
中有更多的代码。在本例中,执行返回
而不是退出(0)
可能是等效的,但在更复杂的代码中就不是这样了;我发布了我所有的代码。谢谢你的建议!现在我明白我做错了什么。非常感谢。接受这个答案。@Arandur:YW。一条额外的建议。当从多进程应用程序执行printf调试时,在每一行上预先设置写入进程的pid。这将使事情更容易理解。
if (pid1 == 0) {
setsid();
run_ping();
exit(EXIT_SUCCESS); // <------ here!
}
void run_monitor(pid_t sibling) {
while (kill(sibling, 0) != -1 and errno != ESRCH) {
//...
}
}
void makeSiblings() {
pid_t pid2 = fork(); //error code ommited
setsid();
if (pid2 != 0)
return;
//this is now the monitor process
while (true) {
pid_t pid1 = fork(); //error code ommited
if (pid1 == 0) {
setsid();
run_ping();
exit(EXIT_SUCCESS);
}
run_monitor(pid1);
}
}