2011-07-23 49 views
14

我有一个简单的程序,使用Qt框架。 它使用QProcess执行RAR并压缩一些文件。在我的计划,我赶上SIGINT和在我的代码做一些事情,当它occures:子进程收到父母的SIGINT

signal(SIGINT, &unix_handler); 

当SIGINT occures,我检查,如果RAR过程就完成了,如果不是我会等待...问题是(我认为)RAR进程也得到了SIGINT,这是为我的程序设计的,它在压缩所有文件之前退出。

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

谢谢

+0

什么操作系统? – Nemo

+0

目前我在Debian 5.0.8上进行测试 – xx77aBs

回答

25

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

您需要使用setpgidsetsid将子进程放入不同的进程组,以便它不会接收控制终端生成的信号。

[编辑]

请务必仔细阅读setpgid页面的基本原理部分。在这里插入所有潜在的竞争条件是有点棘手的。

要保证没有SIGINT将交付给你的孩子的过程100%,你需要做的是这样的:

#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,则必须阻止该信号。如果execl发生在父母有时间做任何事之前发生,您必须在子女中拨打setpgid。如果父级运行,并且有人在子级有时间做任何事情之前点击Ctrl-C,则必须在父级中调用setpgid

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

+0

非常感谢。我认为这是我的问题的答案。我会尽快尝试;) – xx77aBs

+0

它的工作,我刚刚添加正确的包括和这一行:setpgid(rar.pid(),0); – xx77aBs

+0

没问题。请注意,'setpgid'充满了竞争条件,正确使用它有点微妙。我已经更新了我的答案,使其更加完整。 – Nemo

0

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

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

+0

感谢您浏览此页面,我并不知道它。我只是调用quit并等待我的线程,然后退出应用程序。它适用于除RAR以外的所有内容,所以我不认为这是问题所在。但我会阅读这个页面。再次感谢 – xx77aBs