为什么我在没有终端的情况下关闭终端机,却杀死了铬浏览器?


12

这个问题很老,我仍然不清楚为什么。


2014年的原始问题:

在“ Gnome终端”选项卡中,我运行了

$ nohup chromium-browser &

但是,当我关闭终端选项卡时,chromium-browser也会退出。不nohup应该防止这种情况吗?吉尔斯说:

可以说nohup和disown都可以抑制SIGHUP,但是方式不同。nohup使程序最初忽略该信号(程序可能会对此进行更改)。nohup还尝试安排该程序不具有控制终端,以便在终端关闭时内核不会将其发送给SIGHUP。抛弃纯粹是在壳内部;它导致外壳终止时不发送SIGHUP。

那么,nohup不会使铬浏览器忽略SIGHUP吗?

我也在其他可执行文件(例如和Emacs(GUI模式))上看到了这一点。但不是在xeyes上。

发布问题时,这是在32位Ubuntu 12.04上发生的。


2015年更新,

现在我正在运行Ubuntu 14.04,google-chrome而不是已chromium-browser安装。以前发生在铬浏览器上的事情现在也发生在google-chrome上。nohup google-chrome 2>/dev/null &关闭终端选项卡时不会关闭它。/usr/bin/google-chrome是bash脚本的链接/opt/google/chrome/google-chrome。为什么nohup应用于bash脚本不起作用?我们如何使其在bash脚本上起作用?那么Python脚本呢?


1
您应该详细介绍您的环境。我不会重现您的测试用例。
jlliagre 2014年

您还会看到其他哪些可执行文件?尝试一些简单的事情,例如xeyes
沃伦·杨

@WarrenYoung:Emacs(GUI)。但是xeyes可以工作。
蒂姆

Answers:


12

关闭GNOME终端窗口时,会将SIGHUP发送到它正在运行的shell。Shell通常会将SIGHUP发送到它知道创建的每个进程组-甚至是以nohup- 开头的进程组,然后退出。如果shell是bash,它将跳过向用户标记为的任何进程组发送SIGHUP disown

运行带有的命令nohup会使它忽略SIGHUP,但是该过程可以更改它。如果默认情况下将SIGHUP分配给进程,则如果它收到SIGHUP,则该进程将终止。

Linux提供了一些工具来检查正在运行的进程的信号设置。

Chrome浏览器Shell脚本执行已exec编译应用的,因此其进程ID保持不变。因此,要查看其信号设置,我跑了nohup chromium-browser &一下,然后看了/proc/$!/status看信号配置。

SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003

这些是十六进制数字。这表明SIGHUP没有被捕获,也不会被忽略。仅SIGPIPE(SigIgn中的第13位)被忽略。我跟踪到以下代码

// Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
void SetupSignalHandlers() {
  // Sanitise our signal handling state. Signals that were ignored by our
  // parent will also be ignored by us. We also inherit our parent's sigmask.
  sigset_t empty_signal_set;
  CHECK(0 == sigemptyset(&empty_signal_set));
  CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));

  struct sigaction sigact;
  memset(&sigact, 0, sizeof(sigact));
  sigact.sa_handler = SIG_DFL;
  static const int signals_to_reset[] =
      {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
       SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP};  // SIGPIPE is set below.
  for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
    CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
  }

  // Always ignore SIGPIPE.  We check the return value of write().
  CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
}

尽管有评论,但父级忽略的信号不会被忽略。SIGHUP会杀死铬。

解决方法是执行@ xx4h指出的操作:disown在bash中使用命令,以便如果bash必须退出,则不会将SIGHUP发送到chromium-browser进程组。您可以编写一个函数来做到这一点:

mychromium () { /usr/bin/chromium-browser & disown $!; }

谢谢。现在,我主要了解您的意思了。“由于脚本从未重置过该陷阱,因此实际的铬二进制文件将在SIGHUP的处置设置为默认值的情况下调用。” 通过“重置此陷阱”,您是否意味着将SIGHUP的陷阱改回默认值,从而终止该过程?您如何“重置此陷阱”?
2016年

哦,“重置此陷阱”,我的意思是“将该信号的处理方式设置回Shell脚本为其设置处理程序之前的方式”。如果shell这样做了trap "" 1,那将使shell(及其子对象)忽略SIGHUP。我会澄清这一点。
Mark Plotnick

谢谢。澄清后将对其进行检查。我现在试图了解守护进程,nohup,disown和背景,因此我回来重新审视了我以前听不懂的老问题和答复。关于nohup,disown和background的困惑已得到解决,我一直坚持使用daemon的概念以及如何守护进程(请参见下文)。如果您有时间再次提供帮助,我再次感谢。
蒂姆(Tim)


我看了看Chrome应用程序代码,结果发现应用程序中的C ++代码无条件地将SIGHUP重置为默认值。trapShell脚本包装器中的命令不能阻止这种情况,而运行nohup不能阻止这种情况。我将修改答案以反映这一点。
Mark Plotnick

3

如果chromium-browser是像什么google-chrome话,我认为最有可能的问题是,chromium-browser 是不是chromium,但不是一个shell封装初始化状态,那么execŞ chromium

在我的google-chrome安装中,二进制文件实际上位于其中,/opt/google/chrome而其中的包装器/usr/bin只是一个shell脚本,该脚本在设置xdg-*二进制文件本身之前,设置了许多有关默认值和绝对路径等的环境。

在这一点上,nohup可能最初代表它称为其子脚本的脚本忽略的任何信号都将不再重要,除非包装脚本谨慎地安排它否则),则ctty会被继承。

尝试file /usr/bin/chromium-browser检查它是否是我认为的shell脚本。如果是这样,请考虑对其进行重写以使其更适合您。

我可以说,这样做google-chrome 2>/dev/null &可以为我保持打开状态,但是我不记得这是否是我对脚本进行的修改的可能结果-一年多以前。


谢谢。chromium-browser以前发生过的同样事情google-chrome现在也发生过。我没有chromium-browser安装。nohup google-chrome 2>/dev/null &关闭终端选项卡时不会关闭它。google-chrome是一个bash脚本/opt/google/chrome/google-chrome。为什么nohup应用于bash脚本不起作用?我们如何使其在bash脚本上起作用?那么Python脚本呢?
蒂姆(Tim)

好的,它确实可以在脚本上运行,但是脚本在被实际的chrome二进制文件替换之前仅运行了几纳秒。
mikeserv

您是exec在说脚本中实际上是chrome二进制文件吗?那我该如何修改脚本呢?这是我的/opt/google/chrome/google-chrome
Tim

@Tim-是的-看到底部了吗? exec -a "$0" "$HERE/chrome" ... || exec -a "$0" "$HERE/chrome"...在顶部$HERE设置为的值readlink $0 (这是您的安装路径google-chrome),但设置/opt/google/chrome/chrome为二进制文件-脚本将自身替换为二进制文件。
mikeserv

@Tim:至于如何去-你能不能别再exec可能。您将得到一个额外的pid (超过它的1000个)和一个正在等待的shell进程,但是我认为这就是它的范围。否则,您可能会替换execw / nohup。这主要取决于chrome将要忍受的内容-但它应该那样工作。
mikeserv 2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.