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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:14:26  来源:igfitidea点击:

Child process receives parent's SIGINT

c++clinuxunix

提问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 SIGINTand doing something in my code when it occurs:

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

signal(SIGINT, &unix_handler);

When SIGINToccurs, 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 SIGINTthat 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 SIGINTwhen my program receives it?

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

Thanks

谢谢

采纳答案by Nemo

If you are generating the SIGINTwith Ctrl+Con a Unix system, then the signal is being sent to the entire process group.

如果您在 Unix 系统上生成SIGINTwith 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.

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



[Edit:]

[编辑:]

Be sure to read the RATIONALE section of the setpgidpage carefully. It is a little tricky to plug all of the potential race conditions here.

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

To guarantee 100% that no SIGINTwill 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 setpgidin the child in case the execlhappens before the parent has time to do anything. You have to call setpgidin the parent in case the parentruns and someone hits Ctrl+Cbefore the childhas time to do anything.

严格来说,这些步骤中的每一步都是必要的。如果用户在调用 后立即点击Ctrl+,您必须阻止信号。如果在父母有时间做任何事情之前发生这种情况,您必须打电话给孩子。你必须打电话给父母,以防父母跑了,有人在孩子有时间做任何事情之前点击了+ 。CforksetpgidexeclsetpgidCtrlC

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 事件线程之外执行。该页面还提出了一种处理方法。我更喜欢让处理程序将自定义事件“发布”到应用程序并以这种方式处理它。我在这里发布了一个描述如何实现自定义事件的答案。