进程间通信:
每个人进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓存区,进程1将数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制叫做进程间通信(IPC)。
管道:
一种最基本的IPC机制,由pipe函数创建。
#include<unistd.h>
int pipe(int filedes[2]);
调用pipe函数时在内核中开辟一块缓冲区(管道)用于通信,它有一个读端一个写端,通过filedes参数传出给用户程序两个文件描述符,filedes[0]表示指向管道的读端,filedes[1]表示指向管道的写端。所以管道在用户程序看起来就像打开文件一样,通过read(filedes[0])或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0;失败返回-1.
管道通信的一般想法:
1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端。
2、父进程调用fork创建子进程,那么子进程也用两个文件描述符指向同一个管道。
3、父进程关闭管道读端,子进程关闭管道写端。父进程向管道写,子进程向管道读,这样就可以实现坚持间通信。
管道的限制:
两个进程通过一个管道只能实现单向通信。
如果希望双向通信可以再开辟一个管道。
管道的读写端通过打开的文件描述符来传递,因此要通信的两个进程必须从他们大的公共祖先那里继承管道文件描述符。管道通信需要进程之间有关系。
使用管道需要注意的四种特殊情况:
1、如果所用指向管道写端的文件描述符否关闭了(写端的引用计数等于零),但仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
2、如果有指向写端的文件描述符没有关闭(写端的引用计数大于0),但是没有向管道写入数据,这时用进程从管道读数据,那么管道剩余的数据会被读取,再次read会阻塞,直到管道中有数据可读才读取数据返回。
3、如果所有指向管道读端的文件描述符都关闭了(读端的引用计数等于0)这时候有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
4、如果有指向管道读端的文件描述符没关闭(读端的引用计数大于0),但是读端的进程不读取数据,这时进程向管道写入数据,那么在管道写满时,再次write会阻塞,直到管道中有空位置才再次写入数据并返回。
命名管道概念:
命名管道是一个设备文件,只要可以访问路径,就能够通过FIFO相互通信。(FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出)。
命名管道和管道的使用方法基本相同。但因为命名管道是一个存在于硬盘的文件,而管道是存在于内存的特殊文件,在使用命名管道前必须先调用open()函数打开命名管道。
要注意的是,调用open()打开命名管道的进程可能会被阻塞。但是用读写方式(O_RDWR)打开,一定不会阻塞;如果只用读方式(O_RDONLY)打开,则调用open()函数的进程会被阻塞直到有写方打开管道;同样以写方式(O_WRONLY)打开,也会阻塞直到有读方式打开管道。