【问题标题】:How to start a process in its own process group?如何在自己的进程组中启动一个进程?
【发布时间】:2011-08-14 02:54:41
【问题描述】:

我想在它自己的进程组中启动一个进程(或者,一旦启动就改变它的组)并且:

  • 让组中的进程从终端响应Ctrl + C
  • 获取进程组的ID,以便我可以通过kill 命令终止组中的所有进程。

注意:我尝试了setsid prog [args],但进程没有响应终端的 Ctrl+C,也无法获取新的进程组 ID。

我也尝试通过 Perl 的setpgrp($pid, $pid)POSIX::setpgid($pid, $pid) 更改进程组,但无济于事。

编辑:更大的问题:

我有一个进程(单线程;我们称之为“多产”进程P),它同步启动许多子进程(一个接一个;当前一个子进程终止时它会启动一个新进程)。从终端,我希望能够杀死 P 和它下面的进程树。为此,我可以简单地安排杀死P 组中的进程。但是,默认行为是P 在其父进程的组中。这意味着如果我杀死 P 组中的所有进程,P 的父级将被杀死,除非我有 P 并且它的树在它们自己的组中。

我的目的是杀死P 和它下面的树,但不是P 的父级。另外,我不能修改P的代码本身。

【问题讨论】:

  • 请说明您需要完成与进程启动的默认行为(如下面的 ninjalj 观察到的)有什么区别?
  • 我希望我在上面添加的编辑(更大的问题)有助于澄清意图。
  • 您可以forksetpgrp 将进程放在新进程组上。然后,您将拥有 Pp、Pc 和 Pc 的子代,而不是 P 及其子代。由于您在fork 之后立即setpgrp'd Pc,它将位于自己的进程组中,因此您可以一口气杀死它及其子进程。有 Pp wait,它会等到 Pc 死亡然后退出(或任何你想要它做的事情)。
  • 这正是我们所需要的。谢谢!!只剩下一块拼图可以放置到位。我希望我的父 Perl 脚本以指示它被中断的错误状态终止。请在下面的答案部分查看我的帖子。

标签: linux process process-group


【解决方案1】:

“在自己的进程组中启动进程”是什么意思? shell 在它们自己的进程组中启动进程,这就是它执行作业控制的方式(通过为前台进程设置一个进程组,为在后台启动的每个管道设置多个进程组)。

要查看 shell 为每个管道启动一个新进程组,您可以这样做:

ps fax -o pid,pgid,cmd | less

这将显示如下内容:

11816 11816  |   \_ /bin/bash
4759   4759  |       \_ ps fax -o pid,pgid,cmd
4760   4759  |       \_ less

注意,shell 已经为管道创建了一个新的进程组,并且管道中的每个进程都共享该进程组。

编辑:

我想我知道你在说什么。您正在从 Perl 调用 system。显然,sh -c 不会创建新的进程组,因为它是一个没有作业控制的 shell。

我会做的是fork,然后是孩子:

setpgrp;
system("ps fax -o pid,pgid,cmd");

wait 在父级上。

【讨论】:

  • 有趣的一点...目的是什么?自己的进程组或自己的会话ID?我有点假设是后者,但我们必须等待海报澄清
  • @Chris:我认为 OP 使用了 setsid,因为没有任何 setpgrp 实用程序。
  • @ninjalj:可能是这样。我想知道意图是什么。无论如何,我在整理我可能不相关的答案时学到了一些东西;-)
  • @Chris:您的回答相关的。我只是添加了一个不同的角度。
  • @ninjalj:你对 Perl 的想法是正确的。我上面提到的“profilic”进程是一个 Perl 进程,它多次调用 system 。当它的当前子进程终止时,P 创建另一个子进程,忽略前一个子进程被中断的事实。我的目标是安排 P 和它下面的进程树在从终端中断时被杀死,但 不是 P 的父级
【解决方案2】:

编辑:如果您想做的是使用 setsid 但找到结果进程的会话 id 和/或 pid:

如果您通过 setsid 命令启动一个进程,它将不会连接到您的终端,所以它当然不会响应 ctrl-c。

你可以通过 grepping 的输出找到它

ps x -O sid 

或者更有限的东西,比如

ps x -o %c,%p,sid

或者简单地通过 proc/[pid]/stat 来查看所有条目并查看会话 ID 和其他感兴趣的内容(有关详细信息,请参阅 man proc)

setsid 的手册页没有提供任何直接生成输出的标志,但是您可以通过修改标准轻松制作自己的版本来打印所需的信息。

例如,从其中一个结果中获取 setsid.c 的副本

http://www.google.com/codesearch?as_q=setsid&as_package=util-linux

注释掉 nls 包含的语言环境内容和 _("") 错误宏,这会导致问题,然后在 execvp 行之前添加:

    printf("process will be pid %d sid %d\n", getpid(), getsid(0));

【讨论】:

  • 我应该说的是“某些宏在用于显示错误消息的单文件构建中不可用”
【解决方案3】:

这是按照 ninjalj 上述建议的 Perl 代码中的答案:

prolific_wrapper.pl

my $pid = fork();
if (not defined $pid) {

    die 'resources not available';

} elsif ($pid == 0) {

    # CHILD
    setpgrp;
    exit system(prolific => @ARGV);

} else {

    # PARENT
    my $was_killed = 0;
    local $SIG{INT} = sub {
        say 'kill prolific and its tree ...';
        kill KILL => -$pid;
        $was_killed = 1;
    };
    wait;
    my $child_status = $?;
    $SIG{INT} = 'DEFAULT';
    if ($was_killed) {kill INT => $$}
    else {exit $child_status}

}

再次感谢!

【讨论】:

  • 你总是可以kill INT => $$而不是exit,虽然我不确定这样退出是否干净。
  • OTOH perl -e 'kill INT => $$;'; echo $? 在我的盒子里显示 130。所以对我来说是exit 130
  • 无论如何,我不确定您是否需要捕获 SIGINT,^C 应该将其发送到整个进程组,您的子 Perl 进程会忽略它,但它会从 @987654326 获取退出代码@调用。
  • perl -e 'exit system"sleep 5"'; echo $? 和 ^C 可以看到
  • 1.我需要在包装器(父级)中捕获 SIGINT,因为我需要杀死以 prolific 为首的组中的进程。 2. 我会使用出口 130。我不确定kill INT => $$ 在信号处理程序中会产生什么影响。
猜你喜欢
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 2020-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-04
相关资源
最近更新 更多