进程间通信
Linux环境下,进程地址空间相互独立,每个进程拥有各自的用户地址空间。一个进程的全局变量在其它进程中都是看不到的,所以进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内存缓冲区,进程2再从内核缓冲区把数据读走。内核提供的这种机制称为进程间通信(IPC, InterProcess Communication)。
在进程间完成数据传递需要借助操作系统提供特殊的方法,如:管道,命名管道,信号,消息队列,共享内存,信号量,套接字等。常用的进程间通信方式有:
1. 管道(使用最简单)
2. 信号(开销最小)
3. 共享内存区(无血缘关系)
4. 本地套接字(最稳定)
管道/匿名管道(PIPE)
管道的实质
管道的实质是内核利用**环形队列的数据结构在内核缓冲区的一个实现,默认设置大小为4K,可以通过 ulimit -a命令查看。由于利用环形队列进行实现,读和写的位置都是自动增长的,不能随意改变,一个数据只能被读取一次,读取后数据就会从缓冲区中移除。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或者写进程进入等待队列,当空的缓冲区有新数据写入或者满的缓冲区有数据读出来时,就唤醒等待队列中的进程继续读写。管道的通信方式为:写端每次都将数据写入管道缓冲区的 末尾 ,而读端每次都从管道缓冲区的 头部 读出数据。管道对于两端通信的进程来说就只是一种文件,一种不属于文件系统仅存在内存中的“伪文件”管道的局限性
- 管道是半双工,数据只能向一个方向流动,所以只支持单向数据流。
- 只能用于具有亲缘关系(父子进程或者兄弟进程)的进程
- 管道的缓冲区大小有限
- 没有名称
管道的使用介绍
- 创建管道
int pipe(int pipefd[2]);//成功:0;失败:-1,设置errno
函数调用成功返回r/w两个文件描述符。无需open,但需要手动close。规定fd[0]->r; fd[1]->w。
- 父进程调用pipe函数创建管道,得到两个文件描述符fd[0],fd[1]指向管道的读端和写端。
- 父进程调用fork函数创建子进程,那么子进程也有两个文件描述符指向同一管道。
- 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。
总结如下:
-
读管道
管道中有数据,read返回实际读到的字节数
管道中无数据:
管道写端被全部关闭,read返回0(就像读到文件结尾)
管道写端没有全部被关闭,read阻塞等待(可能将有数据抵达,此时会让出CPU) -
写管道
管道读端全部被关闭,进程异常终止(也可使用SIGPIPE信号,使进程不终止)
管道读端没有全部关闭
管道已满,write阻塞
管道未满,write将数据写入,并返回实际写入的字节数。