c - 使用 setpgid 将父进程组设置为子进程组失败

标签 c linux process fork

我正在尝试将进程的 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/

相关文章:

c - 如何有效地将十六进制编码的字符串转换为 C 中的字符串

c - malloc 的内存和 sigsegv

linux - 禁用 SELINUX 选项后无法从 teraterm 连接 Azure Linux VM

linux - Linux 程序的外部禁用信号

java - 从命令行获取java进程的 "user.dir"系统属性

c# - 有时间忽略 IDisposable.Dispose 吗?

c - 重新分配(): getting an invalid pointer error in C

c - 我如何按照 MATLAB 语法编写此 C 代码片段?

linux - Artifactory 网页界面无法访问

Java启动具有受限文件读/写权限的应用程序