关于close()和read()的关系

时间:2015-03-21 10:01:58

标签: c process pipe

int main()
{
    char *msg="hello";
    char buff[MAX];
    int p[2];
    pipe(p);
    int i,pid=fork();
    if(pid>0){
        //close(p[1]);
        read(p[0],buff, MAX);
    }
    else
    {
        printf("child exiting\n");
    }
}

为什么以上代码最终会被阻止?但是如果我们删除评论并放置

close(p[1])

那为什么代码会立即结束?

2 个答案:

答案 0 :(得分:2)

创建管道后,它会有四个结束:

  • 父进程中的阅读结束p[0]
  • 父进程中的写作结束p[1]
  • 子流程中的阅读结束p[0]
  • 子流程中的书写结束p[1]

除非两个写入结束都已关闭,否则UNIX不会将EOF传递给阅读器,因为它知道管道仍然可写。

当子进程退出时,它会关闭管道两端的两端。但是,父级仍然有一个可写端打开,因此从管道块读取而不是向父级提供EOF。这就是UNIX手册指示立即关闭管道的未使用端的原因:

  

使用pipe(2)fork(2)的应用程序应使用合适的close(2)调用来关闭不必要的重复文件描述符;这可以确保在适当的时候传递文件结尾和SIGPIPE / EPIPE

以下是如何在不关闭父级p[1]的情况下阻止程序阻止的示例:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void* write_pipe(void* pp) {
    int* p = (int*)pp;
    char msg[] = "Hello from another thread!";
    write(p[1], msg, sizeof(msg));
    return NULL;
}

int main()
{
    char buff[100];
    int p[2];
    pipe(p);
    int pid=fork();
    if(pid>0){
        pthread_t thread1;
        pthread_create (&thread1, NULL, &write_pipe, (void *)p);
        read(p[0],buff, 100);
        printf("%s\n", buff);
        printf("parent exiting\n");
    }
    else
    {
        printf("child exiting\n");
    }
    return 0;
}

上面的代码从父进程内的线程写入管道的写入端,而不是从子进程写入它。这也是管道的合法使用,说明了为什么UNIX无法传递EOF,除非管道的父级写入端已关闭。

答案 1 :(得分:0)

Read是一个阻塞调用,只有在收到EOF时才会返回。如果你不关闭管道的写端,读取结束将不会得到EOF,因此,程序将保持阻止