Linux下的进程间通信之管道

在Linux下,每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到所以进 程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication).
1、管道(pipe)
管道是一种最基本的IPC机制,由pipe函数创建:

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

调⽤用pipe函数时在内核中开辟一块缓冲区(称为管道)⽤用于通信,它有⼀一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。 开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信:
这里写图片描述
在一个进程调用pipe函数创建管道,得到两个文件描述符指向读端和写段。
这里写图片描述
进程调用fork()创建子进程,那么子进程会继承父进程的文件描述符,所以子进程也有两个文件描述符指向管道两端。因为管道只能进行单向通信,所以关闭父进程的读端和子进程的写端(也可以关闭父进程写端和子进程读端)。如下图
这里写图片描述
这是创建管道进行通信的过程,管道创建好之后再写端写入,在读端就可以读到写入的数据。下面编写代码进行测试。

  1 #include<stdio.h>                                                           
  2 #include<unistd.h>
  3 #include<errno.h>
  4 #include<string.h>
  5 
  6 int main()
  7 {
  8     int _pipe[2];
  9     int ret=pipe(_pipe);    //创建管道
 10     if(ret==-1)
 11     {
 12         printf("create pipe error!");
 13         return 1;
 14     }
 15 
 16     pid_t id=fork();    //创建子进程
 17     if(id<0)
 18     {
 19         printf("fork error!");
 20         return 2;
 21     }
 22     else if(id==0)           //子进程
 23     {
 24         close(_pipe[0]);    //关闭读端
 25         int i=0;
 26         char *_mesg_c=NULL;
 27         while(i<100)
 28        {
 29             _mesg_c="i am child";
 30             write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
 31             sleep(1);
 32             i++;
 33         }
 34     }
 35     else                     //父进程
 36     {
 37         close(_pipe[1]);     //关闭写端
 38         char _mesg[100];
 39         int j=0;
 40         while(j<100)
 41         {
 42             memset(_mesg,'\0',sizeof(_mesg));
 43             read(_pipe[0],_mesg,sizeof(_mesg));
 44             printf("%s\n",_mesg);
 45             j++;
 46         }
 47     }                                                                       
 48     return 0;
 49 }

运行结果如图:
这里写图片描述
其中“i am child”每隔一秒打印一次。

使⽤用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读后,再次read会返回0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的⽂文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写⼊入数据并返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值