在system()内部正确处理信号

问题描述 投票:0回答:1

我一直在阅读“ Linux编程接口”。第27章,程序执行。

我了解作者演示了如何使用systemexec来实现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或伪代码表示。

c signals systems-programming
1个回答
0
投票

您可以安装执行SIGCHLDint 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!");

    }

}
© www.soinside.com 2019 - 2024. All rights reserved.