子进程接收父进程的SIGINT

时间:2011-07-23 21:23:19

标签: c++ c linux unix

我有一个使用Qt Framework的简单程序。 它使用QProcess来执行RAR并压缩一些文件。在我的程序中,我正在捕获SIGINT并在代码中执行某些操作:

signal(SIGINT, &unix_handler);

当SIGINT发生时,我检查RAR进程是否完成,如果不是,我将等待它...问题是(我认为)RAR进程也获得了对我的程序而言的SIGINT在压缩所有文件之前退出。

有没有办法运行RAR进程,以便在我的程序收到它时它不会收到SIGINT?

由于

2 个答案:

答案 0 :(得分:27)

如果您在Unix系统上使用Ctrl-c生成SIGINT,则信号将被发送到整个process group

您需要使用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。如果运行,并且有人在孩子有时间做任何事情之前按Ctrl-C,则必须在父母中调用setpgid

上面的序列很笨拙,但确实可以处理100%的竞争条件。

答案 1 :(得分:0)

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

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