如何通过信号反复重启程序

问题描述 投票:2回答:3

我想要一种方便的方法来重新启动程序。我以为我可以捕获一个信号(在示例中为USR1)并调用exec。

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

char* const* args;
void restart() {
    printf("restarting\n");
    execv(args[0], args);
}

int main(int argc, char* const argv[]) {
    printf("Starting\n");
    args = argv;
    signal(SIGUSR1, restart);
    raise(SIGUSR1); // could use pkill -SIGUSR1 file-name instead
    pause();
    printf("Terminated normally\n");
    return 0;
}

上面的示例有点用。输出是

Starting
restarting
Starting

然后挂起。仍然可以接收其他信号。

我假设我只是无法清除信号。预期的行为是使程序无限期地重新启动。

c linux signals posix
3个回答
1
投票

Linux的man 2 signal解释了使用signal设置信号处理程序时会发生什么。有两种可能性:

  1. 信号的设置被重置为SIG_DFL,然后调用处理程序。要再次处理此信号,您​​需要重新建立信号处理程序。这会按预期工作。

或:

  1. 信号被阻止,然后调用处理程序。当处理程序返回时,信号将被解除阻塞。如果处理程序未返回,则信号仍然被阻止,这就是您正在发生的事情。

因此,一个可以使用您的代码,而另一个则不能。但是,哪两个适用呢?没有可靠的了解方法。 Posix允许两种可能性,并且两种可能性都存在于不同的平台上。因此,Linux手册页建议:

signal()的唯一可移植用途是将信号的处置方式设置为SIG_DFLSIG_IGN ... [D]请勿将其用于[建立信号处理程序的目的]。

POSIX.1通过指定sigaction(2)解决了可移植性问题,它在调用信号处理程序时提供对语义的显式控制;使用该接口代替signal()

这是个好建议。当您更改为使用sigaction时,您可能需要使用上述第一个选项,该选项要求:

sa.sa_flags = SA_RESETHAND | SA_NODEFER

这也来自Linux手册页,非常值得全文阅读。 (当然,sigaction联机帮助页更为相关。)


1
投票

在您的平台上,SIGUSR1在信号处理程序内被屏蔽,这对于signal是典型的但不是强制性的行为(相反,请参见SA_NODEFER and sigaction)。

sigaction,因此SIGUSR1在您的第二次执行中被挂起,从未交付。

[在mask is inherited across the execve顶部,也许在处理程序中尝试这样的操作,以查看发生了什么:

execve

0
投票

不确定为什么会起作用-用信号集替换信号

首先,定义__USER_XOPEN_EXTENDED,否则未定义sigset

main()

将信号更改为信号集

static int
is_blocked(int sig) {
  sigset_t ss;
  sigemptyset(&ss);
  (void)sigprocmask(SIG_BLOCK, NULL, &ss);
  return sigismember(&ss, sig);
}

然后它将继续重新启动,直到被杀死为止。也许有人可以解释为什么sigset起作用而信号不起作用。

© www.soinside.com 2019 - 2024. All rights reserved.