我正在尝试创建一个生成两个进程的程序 - 第一个监视第二个进程,如果它被终止则重新启动它。 (想法是杀死第二个进程的唯一方法是首先杀死第一个进程。)下面我的代码无法实现我的目标。
#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();
}
运行此代码时,会输出Ping.
,例如7812 still exists.
分别每两秒钟一次 - 正如预期的那样。但是,当我来自另一个终端kill 7812
时,“Ping”进程扩散到一个荒谬的程度 - 我似乎是在自我抨击,而且只有通过垃圾邮件killall
我才能够回收
我似乎无法理解有关fork()
或关于setsid()
的一些微妙之处。我会很感激一两个指针。
答案 0 :(得分:2)
是的,你是fork bombimg ...你的函数调用fork()
两次,然后两个孩子最终会递归调用makeSiblings()
。
当第一个孩子,即调用run_ping()
的孩子完成时,它实际上没有完成,但会调用run_monitor()
。然后它会调用makeSiblings()
并重复直到它爆炸!
解决方案是在exit()
之后添加run_ping()
来电:
if (pid1 == 0) {
setsid();
run_ping();
exit(EXIT_SUCCESS); // <------ here!
}
另请注意,您正在makeSiblings()
和run_monitor()
之间进行尾递归,这可能不是一个好主意,因为您的堆栈可能会溢出。
我会写一些类似的东西:
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);
}
}
但现在,您只需使用kill(pid, 0)
代替wait()
,因为ping()
进程是监视器的子进程,应该是它。
答案 1 :(得分:0)
在makeSibling函数中,在第二个if块的末尾添加一个exit(0);或者其他的东西。因为你实际上是叉炸弹。 使用fork时,大多数时候都必须考虑退出。
答案 2 :(得分:0)
... int kill(pid_t pid,int sig); ...如果sig为0(空信号), 执行错误检查但实际上没有发送信号。 null signal可用于检查pid的有效性。 ...
来源:http://linux.die.net/man/3/kill
一方面,您实际上是在创建流程而不会杀死它们。
另一方面,如果你从另一个终端发送的信号没有被杀死但只是打破了无限循环,那么第一个兄弟也将执行第二个分支。