操作系统为用户提供的用于实现进程之间进行通信的方式。
Notes:进程之间是无法直接通信的,因为每一个进程都有自己独立的虚拟地址空间,所以进程具有独立性,无法直接通信。
进程间通信方式种类:管道、共享内存、消息队列、信号量
管道的本质就是在内核中开辟的一块缓冲区(内核中的一块内存),内核的访问只能通过系统调用接口。每个用户都有一个独立的虚拟地址空间,但是内核是共享的。
多个进程通过访问同一块内核中的缓冲区实现通信。
Notes:在Linux下,一切皆文件,所有的东西都是当作文件一样进行操作,通过IO操作完成对管道的访问。
int pipe(pipefd[2]);这个函数形参列表是一个数组,因为管道是一个半双工通信,所以不能确定到底是读还是写,其中pipefd[0]是读,pipefd[1]用于写。这两个操作句柄不能同时使用。
返回值:成功返回0,失败返回-1。
管道的读写特性:
管道符号: | 连接两个命令,将前面命令的打印结果传输给后面的命令进行处理。模拟实现:ps -ef | grep ssh
上述命令中:ps -ef的含义是:获取所有的进程信息,然后输出到标准输出文件。grep ssh的含义是:从标准输入读区数据,进行字符串匹配过滤。如下图:
命名的运行都是创建子进程,让子进程程序替换实现程序功能:
答:本质:内核中的一块缓冲区。原理就是多个进程通过访问同一块缓冲区实现数据传输。
分类:匿名管道、命名管道。匿名管道只能适用于具有亲缘关系的进程间通信,命名管道可以用与同一主机上任意进程之间的通信。
特性:可以选择方向的单向通信。管道提供字节流传输服务(有序的可靠的基于连接的一种流式传输,可靠——>“先进先出”,基于连接——>所有读端关闭,write异常,所有写端关闭,则read返回0不再阻塞)。
Notes:
管道自带同步与互斥:
互斥:通过同一时间对临界资源(大家都能访问到的资源,可以理解为公共资源)的唯一访问实现访问操作安全。临界区:对临界资源访问的这段代码区域
同步:通过一些条件判断让进程对临界资源的访问更加合理有序。
互斥的体现:对管道进行写入操作大小不超过一个宏–>PIPE_BUF(4096个字节)保证操作的原子性。
同步的体现:若管道没有数据,则read阻塞;若管道数据满了,则write阻塞。
管道的生命周期随进程—>不人为干预,所有打开管道的进程退出了,则管道资源被释放。
匿名:Int pipe(int pipe[2]);
命名: int mkfifo(const char *pathname, mode_t mode);
原理:开辟一块物理内存空间,多个进程将同一块内存通过页表映射到自己的虚拟地址空间,通过自己的虚拟地址空间直接进行访问。
操作流程:
1.创建或打开共享内存
2.将共享内存映射到进程的虚拟地址空间
3.通过映射的虚拟地址进行各种内存操作
4.解除映射关系
5.删除共享内存
共享内存的生命周期随内核,不与进程同进退。
#include
int shmget(key_t key, size_t size, int shmflg);
Key:标识符,多个进程通过相同的标识符打开同一块共享内存
Size:创建时候所开辟空间大小,如果已经内存存在,则被忽略。(以内存页为单位,默认是:4096个字节)
Shmflg:打开方式+创建权限(IPC_CREAT | IPC_EXCL | 0664)
返回值:成功:返回非负整数–>操作句柄;失败返回-1。
void *shmat(int shmid, const void shmaddr, int shmflg);
Shmid:shmget返回的操作句柄
Shmaddr:映射地址–通常为NULL;
Shmflg:映射成功后的访问方式:SHM_RDONLY-只读;0-读写
返回值:成功返回映射后的首地址,失败返回(void)-1;
int shmdt(const void *shmaddr); 解除映射关系。Shmaddr:映射后的首地址。
返回值:成功0,失败-1;
int shmctl(int shmid, int cmd, struct shmid_ds *buf);删除共享内存
Shmid:shmget返回的操作句柄,cmd:操作类型–IPC_RMID–标记共享内存为被销毁状态。Buf:同于设置或获取共享内存信息,不使用则置null,返回值对于IPC_RMID则是成功0,失败-1;
本质原理:开辟一块内存空间,多个进程将同一块内存映射到虚拟地址空间,通过自己虚拟地址进行访问,进而实现进程间通信。
特点:最快的进程间通信方式;共享内存的生命周期随内核
注意事项:共享内存是一个临界资源,对共享内存的操作需要注意安全问题。
共享内存通过虚拟地址直接访问虚拟内存实现数据共享,相对于其他方式需要将数据拷贝到内核,使用时拷贝到用户态,少了两次数据拷贝操作。
有个小练习:共享内存代码实现
运行上述两个代码的时候,可以实现使用共享内存实现进程间通信。
Notes:
ipcs 查看进程间通信资源/ipcrm 删除进程间通信资源
-m 针对共享内存的操作
-q 针对消息队列的操作
-s 针对消息队列的操作
-a 针对所有资源的操作