我正在尝试将进程的 pgrp 更改为子进程的 pgrp,以便我可以在父进程上 setsid
。唯一的问题是我不断收到 EPERM
错误代码。根据 htop,这两个进程具有相同的 session 组。
我基于这个 blog post ,因此我可以更改定向到哪个终端输出。
void sig_exit(int signum)
{
_Exit(0);
}
pid_t change_process_group()
{
pid_t child_pid;
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
pid_t parent = getppid();
setpgid(0, getpid());
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
//sleep(5);
//kill(parent, SIGUSR2);
pause();
printf("Shouldn't reach this\n");
}
//sleep(5);
//signal(SIGUSR2, sig_wait);
//pause();
int parent_pid = getpid();
int code = setpgid(parent_pid, child_pid); // need child process group
printf("%s\n", strerror(errno));
setsid();
return child_pid;
}
main()
{
pid_t child = change_process_group();
kill(child, SIGUSR1);
}
注释掉的行是我认为进程可能未按正确顺序执行,但这些似乎无法解决问题。
如何正确使用 setpgid
将父进程的 pgrp 更改为子进程的 pgrp?
最佳答案
这是一个竞争条件,如果您取消注释父项中的 sleep(5)
行,它就会起作用。当您调用 setpgid(parent_pid, child_pid)
时,child_pid
进程组 必须存在。仅仅存在具有 PID child_pid
的进程是不够的:setpgid
需要一个现有的进程组,除非该进程将自己放入自己的组中。如果父级中的 setpgid(parent_pid, child_pid)
在子级中的 setpgid(0, getpid())
之后运行,它将起作用。
sleep 既低效又脆弱,因此 parent 应该等待 child 的通知。信号很脆弱,因为没有很多不同的信号,而且它们可能来自任何地方。在相关进程之间进行通信的一种好方法是管道。由于您在这里只需要一个一次性通知,因此您可以设置一个管道并在父级中从中读取(在父级中关闭写入端)。 parent 将等到 child 写入管道或关闭它。在 child 中,完成准备工作后,只需关闭管道的写入端即可。父级的 read
调用(或 select
如果您需要同时做其他事情)将返回。
概念验证代码:
pid_t change_process_group()
{
pid_t child_pid;
int child_ready_pipe[2];
if (pipe(child_ready_pipe) < 0)
{
perror("pipe");
exit(1);
}
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
close(child_ready_pipe[0]);
sleep(1); // mimic slow start of the child
if (setpgid(0, 0))
perror("child setpgid to create group");
close(child_ready_pipe[1]);
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
pause();
printf("Shouldn't reach this\n");
}
close(child_ready_pipe[1]);
int parent_pid = getpid();
char ignored;
read(child_ready_pipe[0], &ignored, 1);
close(child_ready_pipe[0]);
if (setpgid(parent_pid, child_pid) < 0) // need child process group
perror("parent setpgid");
if (setsid() < 0)
perror("parent setsid");
return child_pid;
}
关于c - 使用 setpgid 将父进程组设置为子进程组失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47521001/