linux 子进程接收父进程的SIGINT

inb24sb2  于 2022-11-02  发布在  Linux
关注(0)|答案(3)|浏览(249)

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

signal(SIGINT, &unix_handler);

SIGINT发生时,我检查RAR进程是否完成,如果不是,我会等待它...问题是,(我认为)RAR进程也得到了SIGINT,这是我的程序,它退出之前,它已经压缩了所有文件。
有没有一种方法来运行RAR进程,使它不接收SIGINT时,我的程序收到它?
谢谢

ttcibm8c

ttcibm8c1#

如果在Unix系统上使用Ctrl+C生成SIGINT,则信号将被发送到整个进程组。
您需要使用setpgidsetsid将子进程放入不同的进程组中,这样它就不会接收到控制终端生成的信号。
[Edit:]
请务必仔细阅读setpgid页面的基本原理部分。在这里插入所有潜在的争用条件有点棘手。
为了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,您必须阻止该信号。如果execl在父进程有时间做任何事情之前发生,您必须在子进程中调用setpgid。如果 parent 运行,并且有人在 * 孩子 * 有时间做任何事情。
上面的序列很笨拙,但它确实处理了100%的争用条件。

i7uaboj4

i7uaboj42#

您在处理程序中做了什么?只有某些Qt函数可以从unix信号处理程序中安全调用。文档中的This page标识了它们是什么。
主要的问题是处理程序将在主Qt事件线程之外执行。该页面还提供了一个处理此问题的方法。我更喜欢让处理程序“发布”一个自定义事件到应用程序,并以这种方式处理它。我发布了一个回答,描述如何实现自定义事件here

z0qdvdin

z0qdvdin3#

只需使子进程 * 忽略 * SIGINT:

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

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

相关问题