我有一个使用Qt框架的简单程序。 它使用QProcess来执行RAR并压缩一些文件。 在我的程序中,我正在捕获SIGINT,并在发生代码时做了一些事情:
signal(SIGINT, &unix_handler);
当SIGINT发生时,我检查RAR进程是否完成,如果不是,我会等待它…问题是(我认为)RAR进程也得到了SIGINT,这是我的程序的意思,它退出之前压缩了所有文件。
有没有办法运行RAR进程,以便它在我的程序收到它时不会收到SIGINT?
谢谢
如果在Unix系统上使用Ctrl-c生成SIGINT
,则信号将被发送到整个进程组 。
您需要使用setpgid或setsid将子进程放入不同的进程组,以便它不会接收到控制终端生成的信号。
[编辑]
请务必仔细阅读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
。 您必须在父项运行时调用父类中的setpgid
,并且在孩子有时间做任何事情之前有人点击Ctrl-C。
上面的序列是笨拙的,但它确实可以处理100%的竞争条件。
你在做什么? 只有某些Qt函数可以从unix信号处理程序中安全地调用。 文档中的这个页面标识了它们是什么。
主要的问题是处理程序将在主Qt事件线程之外执行。 该页面还提出了一个处理这个问题的方法。 我更喜欢让处理程序将“自定义事件”“发布”到应用程序并进行处理。 我发布了一个描述如何在这里实现自定义事件的答案。