注:整理源于爱编程的大丙
1、进程间通信
1、管道
- 管道的本质其实就是内核中的一块内存 (或者叫内核缓冲区),这块缓冲区中的数据存储在一个环形队列中,因为管道在内核里边,因此我们不能直接对其进行任何操作。
- 其实管道操作就是文件 IO 操作,内核中管道的两端分别对应两个文件描述符,通过写端的文件描述符把数据写入到管道中,通过读端的文件描述符将数据从管道中读出来。读写管道的函数就是 Linux 中的文件 IO 函数
- 管道是独立于任何进程的,并且充当了两个进程用于数据通信的载体,只要两个进程能够得到同一个管道的入口和出口(读端和写端的文件描述符),那么他们之间就可以通过管道进行数据的交互。
匿名管道 位于内核中的一块内存
- 匿名管道只能实现有血缘关系的进程间通信:父子进程,兄弟进程,爷孙进程,叔侄进程
- 创建一个匿名的管道, 得到两个可用的文件描述符:int pipe(int pipefd[2]); 成功返回 0,失败返回 -1
- pipefd[0]: 对应管道读端的文件描述符,通过它可以将数据从管道中读出
- pipefd[1]: 对应管道写端的文件描述符,通过它可以将数据写入到管道中
有名管道 在磁盘上有实体文件,文件类型为 p
- 有名管道文件大小永远为 0,因为有名管道也是将数据存储到内存的缓冲区中,打开这个磁盘上的管道文件就可以得到操作有名管道的文件描述符,通过文件描述符读写管道存储在内核中的数据。
- 创建有名管道的方式有两种,一种是通过命令,一种是通过函数。
- mkfifo 有名管道的名字
- int mkfifo(const char *pathname, mode_t mode);
- 有名管道操作需要通过 open () 操作得到读写管道的文件描述符,如果只是读端打开了或者只是写端打开了,进程会阻塞在这里不会向下执行,直到在另一个进程中将管道的对端打开,当前进程的阻塞也就解除了。所以当发现进程阻塞在了 open () 函数上不要感到惊讶。·
写管道的进程
1. 创建有名管道文件
mkfifo("xx",0664)
2. 打开有名管道文件, 打开方式是 o_wronly
int wfd = open("xx", O_WRONLY);
3. 调用write函数写文件 ==> 数据被写入管道中
write(wfd, data, strlen(data));
4. 写完之后关闭文件描述符
close(wfd);
读管道的进程
1. 这两个进程需要操作相同的管道文件
2. 打开有名管道文件, 打开方式是 o_rdonly
int rfd = open("xx", O_RDONLY);
3. 调用read函数读文件 ==> 读管道中的数据
char buf[4096];
read(rfd, buf, sizeof(buf));
4. 读完之后关闭文件描述符
close(rfd);
2、内存映射区
-
和管道不同的是管道对应的内存空间在内核中,而内存映射区对应的内存空间在进程的用户区(用于加载动态库的那个区域) -
进程间通信使用的内存映射区不是一块,而是在每个进程内部都有一块 -
使用内存映射区既可以进程有血缘关系的进程间通信也可以进程没有血缘关系的进程间通信。 -
#include <sys/mman.h> // 创建内存映射区 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
-
内存映射区使用完之后也需要释放,释放函数原型如下 -
int munmap(void *addr, size_t length);
|