为什么当我关闭终端时,尽管 nohup ,铬浏览器还是被杀死?

为什么当我关闭终端时,尽管 nohup ,铬浏览器还是被杀死?

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


2014年的原始问题:

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

$ nohup chromium-browser &

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

nohup 和 disown 都可以说是抑制 SIGHUP,但是方式不同。 nohup 使程序最初忽略该信号(程序可能会改变这一点)。 nohup 还尝试安排程序没有控制终端,这样当终端关闭时,内核就不会发送 SIGHUP 信号。 disown 纯粹是 shell 内部的;它导致 shell 在终止时不发送 SIGHUP。

那么 nohup 不会让 chromium 浏览器忽略 SIGHUP 吗?

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

当问题发布时,这种情况发生在 32 位 Ubuntu 12.04 上。


2015年更新,

现在我正在运行 Ubuntu 14.04,而google-chrome不是chromium-browser安装。以前发生在 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

当您关闭 GNOME 终端窗口时,会向其正在运行的 shell 发送 SIGHUP 信号。 shell 通常会向它知道它创建的每个进程组发送 SIGHUP(即使是启动的进程组nohup),然后退出。如果是,shellbash将跳过向用户标记的任何进程组发送 SIGHUP disown

运行命令nohup会使其忽略 SIGHUP,但进程可以改变这一点。当进程的 SIGHUP 处理是默认的时,如果它收到 SIGHUP,则该进程将被终止。

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

chromium-browser 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 必须退出,它就不会向chromium-browser进程组发送 SIGHUP。您可以编写一个函数来执行此操作:

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

答案2

铬看起来很特别。

nohup chromium-browser & disown在这种情况下应该有效。也可以看看: https://stackoverflow.com/questions/11421810/nohup-doesnt-work-with-chromium

答案3

如果chromium-browser是这样的google-chrome话我认为最有可能的问题是chromium-browser 不是chromium但它是一个 shell 包装器,它先初始化状态,然后初始化execs chromium

在我的google-chrome安装中,二进制文件实际上位于其中/opt/google/chrome,其中的包装器/usr/bin只是一个 shell 脚本,它设置了许多有关xdg-*默认值和绝对路径等的环境,然后再将其替换为正确的二进制文件。

此时,任何nohup最初可能被其作为子脚本调用的脚本忽略的信号都将不再重要,除非包装脚本小心地以其他方式安排它(事实并非如此)ctty 是继承的。

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

我可以说,只是这样做google-chrome 2>/dev/null &就让我保持开放,但我不记得这是否是我对脚本所做修改的可能结果 - 那是一年多前的事了。

相关内容