我试图将进程的pgrp更改为子进程的pgrp,以便我可以在父进程上setsid
。唯一的问题是我不断收到EPERM
错误代码。根据htop,两个进程都有相同的会话组。
我基于此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更改为子进程?
答案 0 :(得分:0)
这是竞争条件,如果您取消注释父级中的sleep(5)
行,它就会起作用。致电setpgid(parent_pid, child_pid)
时,child_pid
流程组必须存在。仅存在具有PID child_pid
的进程是不够的:setpgid
需要现有进程组,除非进程将自己置于其自己的组中。如果父级中的setpgid(parent_pid, child_pid)
在子级中setpgid(0, getpid())
之后运行,则可以正常运行。
睡觉既低效又脆弱,所以父母不应该等待来自孩子的通知。信号很脆弱,因为没有太多不同的信号,它们可能来自任何地方。在相关流程之间进行通信的好方法是管道。由于此处所需的只是一次性通知,因此您可以设置管道并在父级中读取它(写入端在父级中关闭)。父级将等待,直到孩子写入管道或关闭它。在孩子中,当你完成准备工作时,只需关闭管道的写入端。父母的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;
}