system()
的手册页 states “在执行命令期间,SIGCHLD 将被阻止”
在我的代码中,我正在为 SIGCHLD
安装一个处理程序,它向日志中写入一些内容并忽略该信号。我这样做是为了了解在我的日志中退出的子进程并避免僵尸进程。
当我使用 system()
调用时出现问题。有了这个处理程序 system()
总是返回 -1
而不是 child 的退出代码。但根据手册页中的上述引述,system()
应该处理来自子进程的信号。
我做错了什么?
我的代码如下:
static void handleSignal(int signum, siginfo_t* inf, void* ctx) {
cout << "in signal " << signum << endl;
}
int main() {
struct sigaction chldsa, prevchld;
chldsa.sa_sigaction = &handleSignal;
sigemptyset(&chldsa.sa_mask);
chldsa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &chldsa, &prevchld) == -1) {
cout << "Failed setting sigaction SIGCHLD " << errno;
}
int x = system("exit 1");
cout << "RET=" << x << endl;
}
最佳答案
如果您只想摆脱SA_NOCLDWAIT
及其影响,只需在您的结尾收割所有 child SIGCHLD
处理程序。
编辑添加:刚刚验证了以下内容:
pid_t p;
/* Reap all pending child processes */
do {
p = waitpid(-1, NULL, WNOHANG);
} while (p != (pid_t)0 && p != (pid_t)-1);
最后在 SIGCHLD
处理程序中运行时工作正常(已安装 SA_NOCLDSTOP |SA_RESTART | SA_SIGINFO
)。没有僵尸,system()
返回正确的退出状态。
请注意 waitpid()
是一个 async-signal safe Linux 中的函数,根据 POSIX.1-2004,WNOHANG
表示调用永远不会阻塞,因此上述循环是安全的。
但是,由于标准信号没有排队,如果两个或多个进程在正确的时间退出,其中一个在您的父进程中执行 child-reaping 循环之后但在信号处理程序返回之前退出是可能的,一个或多个 child 不会立即收割。但是,当下一个子进程退出时,它们会。为了缓解这种情况,您应该定期运行上述循环,作为程序正常运行的一部分,或者通过定时器中断。循环从不阻塞,消耗的 CPU 时间非常少。
请记住,waitpid(-1, NULL, WNOHANG)
将返回零,如果有活着的 child ,-1
和 errno == ECHILD
如果没有活着的 child ,或者刚刚收割的进程的进程 ID。 (如果你愿意,你可以在你的日志记录中使用循环,使用一个非 NULL 状态指针来捕获每个已经退出的 child 的退出状态,并记录它。你甚至可以将一个周期性计时器挂接到同一个信号处理程序,例如。)
关于c - 将 SA_NOCLDWAIT 设置为 SIGCHLD 后的 Linux system(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17532632/