为什么分叉这个例子不需要互斥?

时间:2015-03-17 16:25:34

标签: c pipe exec fork dup2

我的教授有一个函数的示例代码,它可以用作管道。但他怎样才能确保父母在孩子面前执行而不必使用互斥锁呢?

void
runpipe(int pfd[])
 {
int pid;

switch (pid = fork()) {

case 0: /* child */
    dup2(pfd[0], 0);
    close(pfd[1]);  /* the child does not need this end of the pipe */
    execvp(cmd2[0], cmd2);
    perror(cmd2[0]);

default: /* parent */
    dup2(pfd[1], 1);
    close(pfd[0]);  /* the parent does not need this end of the pipe */
    execvp(cmd1[0], cmd1);
    perror(cmd1[0]);

case -1:
    perror("fork");
    exit(1);
}
}

2 个答案:

答案 0 :(得分:1)

通常无论孩子或父母是先跑还是不重要。

如果父execvp()是第一个并开始写入管道,则一旦管道变满,写入将阻塞,直到孩子读取一些数据。

如果孩子execvp()是第一个并且从管道开始读取,那么读取将同样阻止,直到父母写入一些数据。

作为旁注,父母将在fork()之后首先在现代Linux内核(例如,3.16.0)上运行,但不应该依赖它。 (此外,父级的时间片可能会在fork()之后立即耗尽,使其看起来像是第一次运行。)有些2.4内核首先运行了孩子。

子关闭管道写入端的原因和管道读取端的父级是确保管道的每一端只有一个文件描述符保持打开状态。 (请记住fork(2)重复文件描述符。)这意味着一旦父关闭写结束,子进程将看到文件结束。如果孩子关闭了读取端而父母在此之后尝试写入管道,则父母将收到SIGPIPE

答案 1 :(得分:1)

代码不能确保父项在子项之前执行(从fork开始)。一般来说,没有必要在这个级别强制执行这样的要求。

如果子进程要使用写入管道的数据,那么它可能会阻止尝试从管道读取,直到父进程写入内容。我说“可能”,因为孩子可能故意表现不同。但是,这两个进程可以同时运行,直到该点,或者子进程可以在父进程之前运行直到它阻塞。如果这是一个问题,父母和孩子编写的exec()程序必须在它们之间进行排序。