您的位置:首页 > 运维架构 > Linux

Linux下的进程间通信之管道

2016-09-06 15:51 260 查看
在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会阻塞,直到管道中有空位置了才写⼊入数据并返回。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息