我有一个使用Qt框架的简单程序。它使用QProcess来执行RAR和压缩一些文件。在我的程序中,我捕捉SIGINT,并在它发生时在我的代码中做一些事情:
SIGINT
signal(SIGINT, &unix_handler);
当SIGINT发生时,我检查RAR进程是否完成,如果不是,我会等待它...问题是,(我认为)RAR进程也得到了SIGINT,这是我的程序,它退出之前,它已经压缩了所有文件。有没有一种方法来运行RAR进程,使它不接收SIGINT时,我的程序收到它?谢谢
ttcibm8c1#
如果在Unix系统上使用Ctrl+C生成SIGINT,则信号将被发送到整个进程组。您需要使用setpgid或setsid将子进程放入不同的进程组中,这样它就不会接收到控制终端生成的信号。[Edit:]请务必仔细阅读setpgid页面的基本原理部分。在这里插入所有潜在的争用条件有点棘手。为了100%保证没有SIGINT被传递到子进程,您需要做如下操作:
setpgid
# 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%的争用条件。
fork
execl
i7uaboj42#
您在处理程序中做了什么?只有某些Qt函数可以从unix信号处理程序中安全调用。文档中的This page标识了它们是什么。主要的问题是处理程序将在主Qt事件线程之外执行。该页面还提供了一个处理此问题的方法。我更喜欢让处理程序“发布”一个自定义事件到应用程序,并以这种方式处理它。我发布了一个回答,描述如何实现自定义事件here。
z0qdvdin3#
只需使子进程 * 忽略 * SIGINT:
child_pid = fork(); if (child_pid == 0) { /* child process */ signal(SIGINT, SIG_IGN); execl(...); }
man sigaction:在execve(2)期间,已处理信号的处理被重置为默认值;忽略信号的处理保持不变。
man sigaction
3条答案
按热度按时间ttcibm8c1#
如果在Unix系统上使用Ctrl+C生成
SIGINT
,则信号将被发送到整个进程组。您需要使用setpgid或setsid将子进程放入不同的进程组中,这样它就不会接收到控制终端生成的信号。
[Edit:]
请务必仔细阅读
setpgid
页面的基本原理部分。在这里插入所有潜在的争用条件有点棘手。为了100%保证没有
SIGINT
被传递到子进程,您需要做如下操作:严格说来,以上每一步都是必要的。如果用户在调用
fork
后按下Ctrl+C,您必须阻止该信号。如果execl
在父进程有时间做任何事情之前发生,您必须在子进程中调用setpgid
。如果 parent 运行,并且有人在 * 孩子 * 有时间做任何事情。上面的序列很笨拙,但它确实处理了100%的争用条件。
i7uaboj42#
您在处理程序中做了什么?只有某些Qt函数可以从unix信号处理程序中安全调用。文档中的This page标识了它们是什么。
主要的问题是处理程序将在主Qt事件线程之外执行。该页面还提供了一个处理此问题的方法。我更喜欢让处理程序“发布”一个自定义事件到应用程序,并以这种方式处理它。我发布了一个回答,描述如何实现自定义事件here。
z0qdvdin3#
只需使子进程 * 忽略 * SIGINT:
man sigaction
:在execve(2)期间,已处理信号的处理被重置为默认值;忽略信号的处理保持不变。