Linux 子进程接收父进程的 SIGINT
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6803395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Child process receives parent's SIGINT
提问by xx77aBs
I have one simple program that's using Qt Framework.
It uses QProcess to execute RAR and compress some files. In my program I am catching SIGINT
and doing something in my code when it occurs:
我有一个使用 Qt 框架的简单程序。它使用 QProcess 来执行 RAR 并压缩一些文件。在我的程序中SIGINT
,当它发生时,我在我的代码中捕获并执行某些操作:
signal(SIGINT, &unix_handler);
When SIGINT
occurs, I check if RAR process is done, and if it isn't I will wait for it ... The problem is that (I think) RAR process also gets SIGINT
that was meant for my program and it quits before it has compressed all files.
当SIGINT
发生时,我检查 RAR 进程是否已完成,如果不是,我将等待它......问题是(我认为)RAR 进程也得到SIGINT
了我的程序的意思,它在压缩之前退出所有文件。
Is there a way to run RAR process so that it doesn't receive SIGINT
when my program receives it?
有没有办法运行 RAR 进程,以便SIGINT
在我的程序收到它时它不会收到?
Thanks
谢谢
采纳答案by Nemo
If you are generating the SIGINT
with Ctrl+Con a Unix system, then the signal is being sent to the entire process group.
如果您在 Unix 系统上生成SIGINT
with Ctrl+ C,那么信号将被发送到整个进程组。
You need to use setpgidor setsidto put the child process into a different process group so that it will not receive the signals generated by the controlling terminal.
您需要使用setpgid或setsid将子进程放入不同的进程组,这样它就不会收到控制终端生成的信号。
[Edit:]
[编辑:]
Be sure to read the RATIONALE section of the setpgid
page carefully. It is a little tricky to plug all of the potential race conditions here.
请务必setpgid
仔细阅读页面的基本原理部分。在这里插入所有潜在的竞争条件有点棘手。
To guarantee 100% that no SIGINT
will be delivered to your child process, you need to do something like this:
为了保证 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);
Strictly speaking, every one of these steps is necessary. You have to block the signal in case the user hits Ctrl+Cright after the call to fork
. You have to call setpgid
in the child in case the execl
happens before the parent has time to do anything. You have to call setpgid
in the parent in case the parentruns and someone hits Ctrl+Cbefore the childhas time to do anything.
严格来说,这些步骤中的每一步都是必要的。如果用户在调用 后立即点击Ctrl+,您必须阻止信号。如果在父母有时间做任何事情之前发生这种情况,您必须打电话给孩子。你必须打电话给父母,以防父母跑了,有人在孩子有时间做任何事情之前点击了+ 。Cfork
setpgid
execl
setpgid
CtrlC
The sequence above is clumsy, but it does handle 100% of the race conditions.
上面的序列很笨拙,但它确实处理了 100% 的竞争条件。
回答by Arnold Spence
What are you doing in your handler? There are only certain Qt functions that you can call safely from a unix signal handler. This pagein the documentation identifies what ones they are.
你在你的处理程序中做什么?只有某些 Qt 函数可以安全地从 unix 信号处理程序中调用。文档中的这个页面标识了它们是什么。
The main problem is that the handler will execute outside of the main Qt event thread. That page also proposes a method to deal with this. I prefer getting the handler to "post" a custom event to the application and handle it that way. I posted an answer describing how to implement custom events here.
主要问题是处理程序将在主 Qt 事件线程之外执行。该页面还提出了一种处理方法。我更喜欢让处理程序将自定义事件“发布”到应用程序并以这种方式处理它。我在这里发布了一个描述如何实现自定义事件的答案。