进程间通信之管道--pipe和fifo使用

匿名管道pipe

函数原型:

#include <unistd.h>
int pipe(int fildes[2]);

参数说明

fildes是我们传入的数组,也是一个传出参数。fildes[0]是读端,fildes[1]是写端。

返回值

  • 成功调用返回0。
  • 失败调用返回-1且设置errno.

实例

现在实现一个用父进程读,子进程写的管道例子。

int main(int argc, char const *argv[])
{
    int pipefd[2];
    pipe(pipefd);
    pid_t pid = fork();
    if (pid == 0)
    {
        //子进程写
        //关闭读
        close(pipefd[0]);
        write(pipefd[1], "hello fuck!", 15);
        sleep(1);
    }
    else if (pid > 0)
    {
        //关闭写
        close(pipefd[1]);
        char buf[16] = {0};
        read(pipefd[0], buf, sizeof(buf));
        printf("%s\n", buf);
    }
    return 0;
}

在这个程序执行之后,父进程会读取到子进程所写的数据。在这个简单的例子中看不到什么坑点。

坑点

在亲缘进程中,我们使用管道要注意以下几点。就拿父子进程作为例子:

A2A58E15E35C4D64A2CBE197854CAF45?method=download&shareKey=a7733358f6c5db5e7c93f4c845d28e61

当前情况是,双方都掌控有读写端,都可以操作。
fork之后,共享管道的读写端。我们一方读一方写,最好要自己指定方向,使数据沿着固定的方向流动。如:

27FB4EE9973842B2855D6E61744079C3?method=download&shareKey=8a77a3ec6d27d655071a20a2d707b7b5

我们这样就指定了子进程来写,父进程来读。也就是说,我们仅仅只需要在代码上加上两个Close就可以完成这个功能:close父进程的写端,close子进程的读端。

如果我们不这样会发生什么?

坑点总结

  • 写进程:
    • 读端全部关闭: 在写进程中,如果内核发现读端全部关闭,内核会认为没有人会来读数据,因此杀死写进程,通过发出的SIGPIPE。
    • 读端并未全部关闭: 在写进程中,如果内核发现读端并未全部关闭,会写入数据直到管道满,write会阻塞,等待数据被读取,有地方可写会再写。
  • 读进程:
    • 写端全部关闭: 在读进程中,写端全部关闭,会读取完管道中的数据,然后返回0,表示读到末尾了。和文件读取一致。
    • 写端并未全部关闭: 在读进程中,写端并未全部关闭,如果管道有数据就会读取,没有数据就会阻塞等待写端的写入。

其中特别要注意,写端没有全关闭的时候并且无数据的时候,读端会阻塞等待写。

Note

  • 数据不能反复读取,读了就会被取走。
  • 半双工。
  • 有亲缘关系进程间使用。
  • 可以通过ulimit -a指令查看各种块的限制大小。其中pipe size就是管道的大小。

FIFO有名管道

此管道突破了匿名管道只能亲缘间通信的限制。

可以用命令直接创建一个有名管道:

mkfifo myfifo

就可以看到一个myfifo管道了。Linux下一切皆文件,打开这个管道和打开文件一样,用open函数即可。

下面写了一个读程序和写程序,可以参考:

//读进程,读了就会被取走,可同时执行两次看结果
int main(int argc, char const *argv[])
{
    int fd = open("myfifo", O_RDONLY);
    while (1)
    {
        char buf[128] = {0};
        int ret = read(fd, buf, sizeof(buf));   //如果写端被关闭,读端返回0,就是读到末尾了。
        if (ret)    printf("%s\n", buf);
        else break;
    }
    return 0;
}

写程序如下:

//写进程。
int main(int argc, char const *argv[])
{
    int fd = open("myfifo", O_WRONLY);
    int num = 1;
    while (1)
    {
        char buf[128] = {0};
        sprintf(buf, "read data:%04d", num++);
        write(fd, buf, strlen(buf));
        sleep(1);
    }
    return 0;
}

和普通文件操作并无区别。

Note

假设我们先执行读程序,还没执行写程序时,会阻塞,直到写端被打开。

同理,我们先执行写程序,还没执行读程序时,也会阻塞,知道读端被打开。

以上告诉我们,fifo必须两端都打开的时候才能工作,否则阻塞。

转载于:https://www.cnblogs.com/love-jelly-pig/p/10053054.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值