我一直在阅读“ Linux编程接口”。第27章,程序执行。
我了解作者演示了如何使用system
和exec
来实现fork
调用。但是,具有挑战性的部分是处理信号。我尤其对以下文字感到困惑
首先要考虑的信号是SIGCHLD。假设调用system()也直接创建子代,并且具有为SIGCHLD建立了一个处理程序,该处理程序执行自己的wait()。在这种情况下,当终端产生SIGCHLD信号时由system()创建的子对象的信号主程序的处理程序将被调用并收集孩子的system()有机会调用waitpid()之前的状态。 (这是一竞争条件的示例。)
下面是没有信号处理的代码示例
#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;
}
}
我知道比赛条件是什么,但不了解作者所描述的整个情况。特别是,我不理解什么是“程序调用系统”。什么是“主程序”?哪个进程创建子进程?
有人可以通过举例说明种族问题如何产生吗?用C或伪代码表示。
您可以安装执行SIGCHLD
的int ws; wait(&ws);
处理程序。
如果允许这样的SIGCHLD
处理程序响应SIGCHLD
运行,它将与waitpid
中完成的system
竞争,如果system
不能成功检索子级的退出状态,经理赢得比赛。
因此,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!");
}
}