当前位置: 首页>>技术教程>>正文


更友善/更温和/更微妙的 Killall 等效替代方案(例如 “endall”)?

, , ,

问题描述

如何以比 killall 更温和的方式结束所有同名进程?我不想中断进程,但要给它们时间正确退出。


也可以看看:

How do I kill processes in Ubuntu?

In System monitor, what is the difference between Kill Process and End Process?

Why does killall (sometimes?) needs to be applied twice?

tl;dr

最佳答案

1. `killall` 已经很好了(SIGTERM)

killall 默认发送 SIGTERM 。这已经是一个很好的方法,让应用程序有机会自行清理。 “去死吧,现在!”方法是发送 SIGKILL 信号,这需要将其指定为 killall 的选项。来自 The GNU C Library: Termination Signals

\\n

Macro: int SIGTERM

\\n

[…] It is the normal way to politely ask a program to terminate.

\\n


2. 系统监视器的 “End process” 同样好(SIGTERM 也是如此)

您链接到有关 GNOME 系统监视器的问题。这也确实使用 SIGTERM 来执行 “End process” 操作(我意识到我与该问题的答案相矛盾)。你可以在源码中找到自己验证一下:

data/menus.ui

<item>
  <attribute name="label" translatable="yes">_End</attribute>
  <attribute name="action">win.send-signal-end</attribute>
  <attribute name="accel">&lt;Primary&gt;e</attribute>
  <attribute name="target" type="i">15</attribute>
</item>

这里的15是信号编号。信号 15 是 SIGTERM 。在提出和回答其他问题之前,系统监视器就已经使用了 SIGTERM


技术附录(针对评论)

查看 git blame 的 Github 表示形式,以下是 GNOME 系统监视器源代码中信号拼写方式的更改:

383007f2 24 Jul 2013 用 GAction 参数替换了用于发送信号的重复代码\n 0e766b2d 18 Jul 2013 将进程弹出菜单移植到 GAction\n 97674c79 3 Oct 2012 摆脱 ProcData 结构\n 38c5296c 3 Jul 2011 使源文件之间的缩进一致。\ n

这些都没有从 SIGQUIT 更改为 SIGTERM ,最后一个是在提出链接问题之前。

次佳答案

@hvd 的回答基本上是正确的。为了进一步支持这一点,当您关闭计算机时,init 进程将首先向进程发送 SIGTERM,然后在延迟后发送 SIGKILL(如果它们尚未退出)。进程无法处理/忽略 SIGKILL

不过,更详细地说,真正的答案是您无法确定程序是否会处理它。 SIGTERM 是最常用的信号,用于礼貌地要求程序退出,但所有信号处理都取决于程序对信号执行某些操作。

换句话说,根据其他答案,如果您有一个由 @Jos 或 @AlexGreg 编写的程序,那么他们可能会处理 SIGQUIT 但可能不会处理 SIGTERM ,因此发送 SIGTERM 的 “soft” 会比 SIGQUIT 少。

我已经编写了一些代码,因此您可以自己尝试一下。将以下内容保存为 signal-test.c ,然后使用

gcc -o signal-test signal-test.c

然后您可以运行它 ./signal-test ,并查看当您使用 killall -s <signal> 发送不同信号时会发生什么。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int flag = 0;

void handle_signal(int s)
{
    flag = s;
}

int main(int argc, char *argv[])
{
    signal(SIGTERM, handle_signal);
    signal(SIGQUIT, handle_signal);

    while(flag == 0){
        sleep(1);
    }
    printf("flag is %d\n", flag);
    return flag;
}

就目前而言,代码可以优雅地处理 SIGTERM 和 SIGQUIT。您可以尝试注释掉 signal(SIG... 行(在行开头使用 //)以删除信号处理程序,然后再次运行并发送信号。您应该能够看到这些不同的输出:

$ ./signal-test
Terminated

$ ./signal-test
Quit (core dumped)

$ ./signal-test
flag is 15

$ ./signal-test
flag is 3

取决于您是否处理信号。

您也可以尝试忽略这些信号:

signal(SIGTERM, SIG_IGN);

如果您这样做,那么发送 SIGTERM 将不会执行任何操作,您必须使用 SIGKILL 来结束该进程。

更多详细信息请参见 man 7 signal 。请注意,以这种方式使用 signal() 被认为是不可移植的 – 但它比其他方法要容易得多!

另一个小脚注 – 在 Solaris 上 killall 尝试终止所有进程。他们全部。如果您以 root 身份运行它,那么您可能会感到惊讶:)

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/14447.html,未经允许,请勿转载。