【问题标题】:Confusion about a implementation of the system function in Unix [duplicate]关于在 Unix 中实现系统功能的困惑 [重复]
【发布时间】:2019-03-19 03:19:53
【问题描述】:

来自 APUE 的 Unix system 函数的实现:

图 8.22 system 函数,没有信号处理

#include    <sys/wait.h>
#include    <errno.h>
#include    <unistd.h>

int
system(const char *cmdstring)   /* version without signal handling */
{
    pid_t   pid;
    int     status;

    if (cmdstring == NULL)
        return(1);      /* always a command processor with UNIX */

    if ((pid = fork()) < 0) {
        status = -1;    /* probably out of processes */
    } else if (pid == 0) {              /* child */
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        _exit(127);     /* execl error */
    } else {                            /* parent */
        while (waitpid(pid, &status, 0) < 0) {
            if (errno != EINTR) {
                status = -1; /* error other than EINTR from waitpid() */
                break;
            }
        }

        // if(waitpid(pid, &status, 0) < 0){
        //     if(errno != EINTR){
        //         status = -1;
        //     }
        // } 
    }

    return(status);
}

为什么它对waitpid 使用while 循环而不是我在cmets 中添加的if 语句?我试过if,到目前为止没有出错。

【问题讨论】:

  • 事实上所有阻塞系统调用可以返回EINTR,你需要重试。
  • @AnttiHaapala 嗯,如man waitpid中所述,如果一个进程被信号停止或恢复,这种状态变化将被waitpid捕获,但是它们被认为是waitpid的成功返回,这2种信号与我们所说的EINTP中断信号不一样,是吗?对吗?
  • 这些是等待进程的信号,这里我们讨论的是运行waitpid的进程接收到的信号。
  • 再一次,正如重复中所解释的那样,EINT R 此处的处理并非特定于 waitpid,而是 any 阻塞系统调用可能会失败,您需要准备重试。
  • 不,如果孩子只是停止(未终止)或恢复,它根本不会返回,因为标志(第三个参数)设置为 0

标签: c unix


【解决方案1】:

除了子进程结束之外,如果waitpid 函数被信号中断,它可能会提前返回。如果发生这种情况,if 块将不会被输入,waitpid 将再次尝试。

如果没有循环,如果waitpid 被中断,您最终会处于父进程不等待子进程的状态,而当子进程退出时,您最终会出现僵尸进程。在父进程退出之前,该僵尸不会被清理,此时 init 进程将成为父进程并自动等待僵尸。

【讨论】:

  • @Rick 不,孩子的终止不会导致错误状态。这将是一个成功的调用!
  • 嗨@dbush,今天我了解到大多数BSD和linux都有自动重启机制,所以再次回到这个问题,我为什么要写循环? 1.默认情况下waitpid会自动重启。 2. 而且这里没有用户定义的信号处理函数,所以不会捕获任何信号,所以我认为父进程中的任何系统调用都不会被中断。
  • @Rick Linux 上的自动重启仅在使用SA_RESTART 标志设置信号处理程序时才会发生,因此它不是默认行为。此示例可能适用于不假设其他信号处理程序的一般情况。
  • 是的,我也认为这个例子是通用的,不是特别基于BSD和linux(作者有时以Solaris为例)。再次感谢你~
  • @Rick 如果您知道这段代码不会用作具有信号处理程序的更大代码库的一部分,那么在这种情况下,您不需要循环,因为信号将终止过程。如果此代码是库的一部分,那么您必须考虑这种情况。
猜你喜欢
  • 2017-04-25
  • 2017-03-06
  • 1970-01-01
  • 2020-10-11
  • 2022-07-17
  • 2020-12-25
  • 2012-09-28
  • 1970-01-01
  • 2020-03-31
相关资源
最近更新 更多