【发布时间】:2020-09-13 03:44:50
【问题描述】:
我已使用此代码示例在超时期限后自动终止子进程,但是当有多个子进程时它不起作用(此代码在线程池中运行)。一个子进程终止后,以下子进程在超时期限后不会终止,并继续直到它们正常退出。所以我会想象电线在某处交叉。我从这个问题的答案得出了这个结论:Waitpid equivalent with timeout?。完整代码示例:
https://www.linuxprogrammingblog.com/code-examples/signal-waiting-sigtimedwait
/* The program creates a child process and waits for it to finish. If a timeout
* elapses the child is killed. Waiting is done using sigtimedwait(). Race
* condition is avoided by blocking the SIGCHLD signal before fork().
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
static pid_t fork_child (void)
{
int p = fork ();
if (p == -1) {
perror ("fork");
exit (1);
}
if (p == 0) {
puts ("child: sleeping...");
sleep (10);
puts ("child: exiting");
exit (0);
}
return p;
}
int main (int argc, char *argv[])
{
sigset_t mask;
sigset_t orig_mask;
struct timespec timeout;
pid_t pid;
sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) {
perror ("sigprocmask");
return 1;
}
pid = fork_child ();
timeout.tv_sec = 5;
timeout.tv_nsec = 0;
do {
if (sigtimedwait(&mask, NULL, &timeout) < 0) {
if (errno == EINTR) {
/* Interrupted by a signal other than SIGCHLD. */
continue;
}
else if (errno == EAGAIN) {
printf ("Timeout, killing child\n");
kill (pid, SIGKILL);
}
else {
perror ("sigtimedwait");
return 1;
}
}
break;
} while (1);
if (waitpid(pid, NULL, 0) < 0) {
perror ("waitpid");
return 1;
}
return 0;
}
【问题讨论】:
-
请比“不起作用”更好地描述问题。确切的预期行为和实际行为是什么?例如,您描述的问题是针对多个子进程,但显示的代码从不创建多个子进程。
-
“此代码在线程池中运行”。您需要显示minimal reproducible example。谁说线程代码没有问题?所以我们需要查看准确可以重现问题的代码。
-
如果您有多个线程尝试使用该方法同时等待子进程,那么遇到问题我并不感到惊讶。然后,您不能假设特定子级的
SIGCHLD将由尝试等待该子级的线程处理。 -
@JohnBollinger 在多线程中等待子进程的更好方法是什么?
-
... 执行子运行时间限制?这很棘手。您肯定需要共享数据来跟踪哪个线程正在等待哪个孩子,以及在杀死孩子之前愿意等待多长时间。然后我会考虑有一个单独的线程专门用于代表所有其他人处理子进程管理职责。这会很复杂,但我认为不如尝试没有专门的线程来做。
标签: c