在 system() 内部正确处理信号
Treating signals correctly inside system()
我一直在阅读"The Linux Programming Interface"。第 27 章,程序执行。
我了解到作者演示了我们如何使用 exec
和 fork
实现 system
调用。然而,具有挑战性的部分是处理信号。特别是我对以下文字感到困惑
The first signal to consider is SIGCHLD. Suppose that the program
calling system() is also directly creating children, and has
established a handler for SIGCHLD that performs its own wait(). In
this situation, when a SIGCHLD signal is generated by the termination
of the child created by system(), it is possible that the signal
handler of the main program will be invoked and collect the child’s
status before system() has a chance to call waitpid(). (This is an
example of a race condition.)
以下是没有信号处理的代码示例
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int system(char *command)
{
int status;
pid_t childPid;
switch(childPid = fork())
{
case -1: /* Error */
return -1;
case 0: /* Child */
execl("/bin/sh", "sh", "-c", command, (char*) NULL);
_exit(127); /* If reached this line than execl failed*/
default: /* Parent */
if (waitpid(childPid), &status, 0) == -1)
return -1;
else
return status;
}
}
我知道什么是竞争条件主义,但不理解作者描述的整个场景。特别是,我不明白 "the program calling system" 可能是什么。 "main program" 是什么?哪个进程创建子进程?
有人可以举例说明竞争条件是如何产生的吗?在 C 或伪代码中。
您可以安装一个 SIGCHLD
处理程序来执行 int ws; wait(&ws);
。
如果允许这样的 SIGCHLD
处理程序 运行 响应 SIGCHLD
,它将与 system
中完成的 waitpid
竞争,如果处理程序赢得比赛,则阻止 system
成功检索 child 的退出状态。
因此,POSIX 规定 SIGCHLD
在 system
中被阻止。
您仍然可以与在其他信号处理程序或其他线程中完成的 wait
调用竞争,但这将是一个设计错误,POSIX
系统不会帮助您。
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
int system(char *command)
{
int status;
pid_t childPid;
switch(childPid = fork())
{
case -1: /* Error */
return -1;
case 0: /* Child */
execl("/bin/sh", "sh", "-c", command, (char*) NULL);
_exit(127); /* If reached this line than execl failed*/
default: /* Parent */
/*usleep(1);*/
if (waitpid(childPid, &status, 0) == -1)
return -1;
else
return status;
}
}
void sigchld(int Sig){ int er=errno; wait(0); errno=er; }
int main()
{
/*main program*/
//main program has a sigchld handler
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = sigchld;
sigaction(SIGCHLD, &sa,0);
for(;;){
//the handler may occasionally steal the child status
if(0>system("true") && errno==ECHILD)
puts("Child status stolen!");
}
}
我一直在阅读"The Linux Programming Interface"。第 27 章,程序执行。
我了解到作者演示了我们如何使用 exec
和 fork
实现 system
调用。然而,具有挑战性的部分是处理信号。特别是我对以下文字感到困惑
The first signal to consider is SIGCHLD. Suppose that the program calling system() is also directly creating children, and has established a handler for SIGCHLD that performs its own wait(). In this situation, when a SIGCHLD signal is generated by the termination of the child created by system(), it is possible that the signal handler of the main program will be invoked and collect the child’s status before system() has a chance to call waitpid(). (This is an example of a race condition.)
以下是没有信号处理的代码示例
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int system(char *command)
{
int status;
pid_t childPid;
switch(childPid = fork())
{
case -1: /* Error */
return -1;
case 0: /* Child */
execl("/bin/sh", "sh", "-c", command, (char*) NULL);
_exit(127); /* If reached this line than execl failed*/
default: /* Parent */
if (waitpid(childPid), &status, 0) == -1)
return -1;
else
return status;
}
}
我知道什么是竞争条件主义,但不理解作者描述的整个场景。特别是,我不明白 "the program calling system" 可能是什么。 "main program" 是什么?哪个进程创建子进程?
有人可以举例说明竞争条件是如何产生的吗?在 C 或伪代码中。
您可以安装一个 SIGCHLD
处理程序来执行 int ws; wait(&ws);
。
如果允许这样的 SIGCHLD
处理程序 运行 响应 SIGCHLD
,它将与 system
中完成的 waitpid
竞争,如果处理程序赢得比赛,则阻止 system
成功检索 child 的退出状态。
因此,POSIX 规定 SIGCHLD
在 system
中被阻止。
您仍然可以与在其他信号处理程序或其他线程中完成的 wait
调用竞争,但这将是一个设计错误,POSIX
系统不会帮助您。
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
int system(char *command)
{
int status;
pid_t childPid;
switch(childPid = fork())
{
case -1: /* Error */
return -1;
case 0: /* Child */
execl("/bin/sh", "sh", "-c", command, (char*) NULL);
_exit(127); /* If reached this line than execl failed*/
default: /* Parent */
/*usleep(1);*/
if (waitpid(childPid, &status, 0) == -1)
return -1;
else
return status;
}
}
void sigchld(int Sig){ int er=errno; wait(0); errno=er; }
int main()
{
/*main program*/
//main program has a sigchld handler
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = sigchld;
sigaction(SIGCHLD, &sa,0);
for(;;){
//the handler may occasionally steal the child status
if(0>system("true") && errno==ECHILD)
puts("Child status stolen!");
}
}