子进程接收到父进程的SIGINT信号

18

我有一个简单的程序,使用Qt框架。它使用QProcess来执行RAR并压缩一些文件。在我的程序中,我捕获 SIGINT 并在它发生时在我的代码中做一些事情:

signal(SIGINT, &unix_handler);

当发生SIGINT信号时,我会检查RAR进程是否完成,如果没有完成,我将等待它...问题在于(我认为)RAR进程也收到了本应该发送给我的程序的SIGINT信号,导致它在没有压缩所有文件的情况下退出。

有没有一种方法可以运行RAR进程,使其在我的程序接收到SIGINT信号时不接收同样的信号?

谢谢


目前我正在Debian 5.0.8上进行测试。 - xx77aBs
3个回答

35
如果你在Unix系统上使用Ctrl+C生成 SIGINT 信号,则该信号将被发送到整个进程组。你需要使用setpgidsetsid将子进程放置在不同的进程组中,以便它不会接收由控制终端生成的信号。

[编辑:]

确保仔细阅读setpgid页面的RATIONALE部分。 在这里插入所有潜在的竞争条件有点棘手。

为了确保100%不向子进程传递任何SIGINT信号,你需要执行类似以下方法的操作:

#define CHECK(x) if(!(x)) { perror(#x " failed"); abort(); /* or whatever */ }
/* Block SIGINT. */
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
CHECK(sigprocmask(SIG_BLOCK, &mask, &omask) == 0);

/* Spawn child. */
pid_t child_pid = fork();
CHECK(child_pid >= 0);
if (child_pid == 0) {
    /* Child */
    CHECK(setpgid(0, 0) == 0);
    execl(...);
    abort();
}
/* Parent */
if (setpgid(child_pid, child_pid) < 0 && errno != EACCES)
    abort(); /* or whatever */
/* Unblock SIGINT */
CHECK(sigprocmask(SIG_SETMASK, &omask, NULL) == 0);
严格来说,这些步骤每一个都是必要的。您需要在调用fork后立即阻止信号以防用户按下Ctrl+C。您需要在子进程中调用setpgid,以防execl发生在父进程还没有时间执行操作之前。您需要在父进程中调用setpgid,以防在子进程还没有时间执行任何操作之前,父进程运行并有人按下Ctrl+C
上述序列很笨拙,但它确实处理了100%的竞争条件。

非常感谢。我认为这是我的问题的答案。我会尽快尝试它 ;) - xx77aBs
感谢您提供的额外信息 ;) - xx77aBs
1
@Jan:嗯,关于assert适用于“只有在程序中存在错误时才为真”的表达式,我持不同意见。在这种情况下,setpgid(0,0)只有在C库或内核中存在错误时才会失败,使用assert检查这种“不可能”的情况是完全合理的。但你说得对,有副作用的问题。我原以为assert(x)保证会评估x,但我错了。我已经恢复到你的版本。 - Nemo
如果子进程因为信号解除只在父进程中完成而被优先于父进程并挂起,那么这不会成为一个问题吗? - Sarien
@Nemo 好的,但是它可能会长时间运行而无法接收信号,对吧? - Sarien
显示剩余10条评论

0

只需使子进程 忽略 SIGINT 信号:

child_pid = fork();
if (child_pid == 0) {
   /* child process */
   signal(SIGINT, SIG_IGN);
   execl(...);
}

man sigaction:

在执行execve(2)期间,处理信号的处置将被重置为默认值;忽略信号的处置保持不变。


0

在您的处理程序中正在做什么?只有某些Qt函数可以从Unix信号处理程序中安全调用。 文档 中标识了它们是哪些。

主要问题是处理程序将在主Qt事件线程之外执行。该页面还提出了一种处理方法。我更喜欢让处理程序“发布”自定义事件到应用程序并以这种方式处理它。我发表了一个答案,说明如何实现自定义事件这里


谢谢您提供这个页面,我之前不知道它的存在。我只是在我的线程上调用了quit和wait方法,然后退出应用程序。这对除了RAR之外的所有东西都有效,所以我不认为这是问题所在。但我会阅读这个页面。再次感谢。 - xx77aBs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接