进程间通信-管道 IPC pipe

进程间通信-管道 IPC pipe

@(Linux)

参考

http://akaedu.github.io/book/ch30s04.html#id2868153

问题1

在例 30.7 “管道”中,父进程只用到写端,因而把读端关闭,子进程只用到读端,因而把写端关闭,然后互相通信,不使用的读端或写端必须关闭,请读者想一想如果不关闭会有什么问题。

如果不关闭,后面写的会把前面写的覆盖。

而且由于不能控制多进程的流程,有可能自己读了自己的内容,没读到对方传来的内容。

问题2

请读者修改例 30.7 “管道”的代码和实验条件,验证我上面所说的四种特殊情况。

情况1

所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXLINE 80

int main()
{
    int n;
    int fd[2];
    pid_t pid;
    char linep[MAXLINE];
    char linec[MAXLINE];

    if (pipe(fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    if ((pid = fork()) < 0)
    {
        perror("fork");
        exit(1);
    }
    if (pid > 0)// parent, write
    {
        close(fd[0]);
        //sleep(1);
        write(fd[1], "hello child", 11);
        close(fd[1]);
        //read(fd[0], linep, MAXLINE);
        //printf("now the parent read: %s\n", linep);
        wait(NULL);

    }
    else// child, read
    {
        close(fd[1]);
        //write(fd[1], "hi parent", 9);
        int res0 = read(fd[0], linec, MAXLINE);
        printf("res0 = %d, now the child read: %s\n", res0, linec);
        int res1 = read(fd[0], linec, MAXLINE);
        printf("res1 = %d, now the child read: %s\n", res1, linec);
        //sleep(1);
    }
    return 0;
}

情况2

如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

int main()
{
    int n;
    int fd[2];
    pid_t pid;
    char linep[MAXLINE];
    char linec[MAXLINE];

    if (pipe(fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    if ((pid = fork()) < 0)
    {
        perror("fork");
        exit(1);
    }
    if (pid > 0)// parent, write
    {
        close(fd[0]);
        sleep(10);
        write(fd[1], "hello child", 11);
        close(fd[1]);
        //read(fd[0], linep, MAXLINE);
        //printf("now the parent read: %s\n", linep);
        wait(NULL);

    }
    else// child, read
    {
        close(fd[1]);
        //write(fd[1], "hi parent", 9);
        printf("child blocked, waiting..\n");
        int res0 = read(fd[0], linec, MAXLINE);
        printf("res0 = %d, now the child read: %s\n", res0, linec);
        //int res1 = read(fd[0], linec, MAXLINE);
        //printf("res1 = %d, now the child read: %s\n", res1, linec);
        //sleep(1);
    }
    return 0;
}

情况3

如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。在第 33 章 信号会讲到怎样使SIGPIPE信号不终止进程。

int main()
{
    int n;
    int fd[2];
    pid_t pid;
    char linep[MAXLINE];
    char linec[MAXLINE];

    if (pipe(fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    if ((pid = fork()) < 0)
    {
        perror("fork");
        exit(1);
    }
    if (pid > 0)// parent, write
    {
        close(fd[0]);
        sleep(1);
        int res = write(fd[1], "hello child", 11);
        printf("write res: %d\n", res);
        close(fd[1]);
        //read(fd[0], linep, MAXLINE);
        //printf("now the parent read: %s\n", linep);
        wait(NULL);

    }
    else// child, read
    {
        close(fd[1]);
        close(fd[0]);
        //write(fd[1], "hi parent", 9);
        //printf("child blocked, waiting..\n");
        //int res0 = read(fd[0], linec, MAXLINE);
        //printf("res0 = %d, now the child read: %s\n", res0, linec);
        //int res1 = read(fd[0], linec, MAXLINE);
        //printf("res1 = %d, now the child read: %s\n", res1, linec);
        //sleep(1);
    }
    return 0;
}

情况4

如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。

int main()
{
    int n;
    int fd[2];
    pid_t pid;
    char linep[MAXLINE];
    char linec[MAXLINE];

    if (pipe(fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    if ((pid = fork()) < 0)
    {
        perror("fork");
        exit(1);
    }
    if (pid > 0)// parent, write
    {
        close(fd[0]);
        for (int i = 0; ; i++)
        {
            int res = write(fd[1], "hello child 11111111", 20);
            printf("%d th write res: %d\n",i, res);
        }
        close(fd[1]);
        //read(fd[0], linep, MAXLINE);
        //printf("now the parent read: %s\n", linep);
        wait(NULL);

    }
    else// child, read
    {
        close(fd[1]);
        printf("child blocked, waiting..\n");
        sleep(5);
        while (1)
        {
            int res0 = read(fd[0], linec, MAXLINE);
            printf("# read res0 = %d, now the child read: %s\n", res0, linec);
            sleep(1);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值