我的 POSIX 信号处理程序中的竞争条件
以下程序分叉出一个子程序,该子程序重复运行“/bin/sleep 10”。父级安装 SIGINT 信号处理程序,将 SIGINT 传递给子级。然而,有时向子进程发送 SIGINT 会失败。这是为什么?我想念什么?
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t foreground_pid = 0;
void sigint_handler(int sig)
{
printf("sigint_handler: Sending SIGINT to process %d\n",
foreground_pid);
if ((foreground_pid != 0) && kill(foreground_pid, SIGCONT) == -1) {
perror("sending SIGINT to forground process failed");
printf("foreground_pid == %d", foreground_pid);
exit(EXIT_FAILURE);
}
foreground_pid = 0;
}
int main(int argc, const char *argv[])
{
while (1) {
pid_t child_pid;
if ((child_pid = fork()) == -1) {
perror("fork failed");
exit(EXIT_FAILURE);
}
if (child_pid) { /* parent */
foreground_pid = child_pid;
printf("waiting for child (%d) to complete ...\n", child_pid);
fflush(stdout);
/* install SIGINT signal handler */
struct sigaction sa;
struct sigaction old_handler;
sa.sa_handler = sigint_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_RESETHAND;
sigaction(SIGINT, &sa, NULL);
int status = 0;
/* wait for child to finish */
if (waitpid(child_pid, &status, 0) == -1) {
perror("waitpid failed");
exit(EXIT_FAILURE);
}
printf(" done.\n");
fflush(stdout);
}
else { /* child */
char * const argv[] = { "/bin/sleep", "10", NULL};
if (execve(argv[0], argv, NULL) == -1) {
perror("execve failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
}
return EXIT_SUCCESS;
}
% make && ./foo
gcc -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L foo.c -o foo
waiting for child (4582) to complete ...
^Csigint_handler: Sending SIGINT to process 4582
done.
waiting for child (4583) to complete ...
^Csigint_handler: Sending SIGINT to process 4583
sending SIGINT to forground process failed: No such process
foreground_pid == 4583
The following program forks off a child, that runs "/bin/sleep 10" repeatedly. The parent installs a signal handler for SIGINT, that delivers SIGINT to the child. However sometimes sending SIGINT to the child fails. Why is that and what do I miss?
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t foreground_pid = 0;
void sigint_handler(int sig)
{
printf("sigint_handler: Sending SIGINT to process %d\n",
foreground_pid);
if ((foreground_pid != 0) && kill(foreground_pid, SIGCONT) == -1) {
perror("sending SIGINT to forground process failed");
printf("foreground_pid == %d", foreground_pid);
exit(EXIT_FAILURE);
}
foreground_pid = 0;
}
int main(int argc, const char *argv[])
{
while (1) {
pid_t child_pid;
if ((child_pid = fork()) == -1) {
perror("fork failed");
exit(EXIT_FAILURE);
}
if (child_pid) { /* parent */
foreground_pid = child_pid;
printf("waiting for child (%d) to complete ...\n", child_pid);
fflush(stdout);
/* install SIGINT signal handler */
struct sigaction sa;
struct sigaction old_handler;
sa.sa_handler = sigint_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_RESETHAND;
sigaction(SIGINT, &sa, NULL);
int status = 0;
/* wait for child to finish */
if (waitpid(child_pid, &status, 0) == -1) {
perror("waitpid failed");
exit(EXIT_FAILURE);
}
printf(" done.\n");
fflush(stdout);
}
else { /* child */
char * const argv[] = { "/bin/sleep", "10", NULL};
if (execve(argv[0], argv, NULL) == -1) {
perror("execve failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
}
return EXIT_SUCCESS;
}
% make && ./foo
gcc -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L foo.c -o foo
waiting for child (4582) to complete ...
^Csigint_handler: Sending SIGINT to process 4582
done.
waiting for child (4583) to complete ...
^Csigint_handler: Sending SIGINT to process 4583
sending SIGINT to forground process failed: No such process
foreground_pid == 4583
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您键入 Ctrl + C 时,tty 驱动程序会对整个进程组执行
SIGINT
;这包括子进程,该子进程将响应它而退出,因为它没有安装处理程序。因此,您正在重复已经完成的操作,并且当父级尝试kill()
时子级是否仍然存在,这是一个冒险的事情。The tty driver performs a
SIGINT
on the entire process group when you type Ctrl + C; this includes the child process, which will exit in response to it because it doesn't have a handler installed. So you're duplicating what is already being done, and whether the child is still around when the parent tries tokill()
it is something of a crapshoot.