目录
-
进程的关系
-
有亲缘关系的进程(related process)
- 父子/兄弟
- 匿名管道/Sys V IPC
-
没有亲缘关系的进程
- 命名管道/Sys V IPC
-
IPC进程间通信
- 进程之间数据交换
-
-
通信的方式
-
单工
- 数据流的方向只能流向一端
-
半双工
- 数据流的方向可以流向两端,但是都是只能选择一个方向
-
全双工
- 数据流的方向可以流向两端
-
-
PIPE/FIFO管道 (半双工)
-
查看管道
- man 7 pipe
-
管道的性质与行为
- pipe匿名管道
- 通过pipe(2)函数创建
- 分读端写端,数据从读端读,写端写
- 管道必须凑齐读写双方
- 读空管道,read(2)阻塞
- 写满管道,write(2)会阻塞
- 如果所有的写端关闭,read会读到eof,并返回0
- 如果所有的读端关闭,write会产生一个SIGPIPE信号,如果信号被忽略,write函数会返回-1并设置errno为EPIPE
- 有容量的,默认大小是65535bytes
-
// Date:2023.09.05 10:11:53
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#define handler_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while(0)
/* 匿名管道的使用 简单常用 */
int main(void)
{
pid_t pid;
int pip[2] = {};
if(-1 == pipe(pip))
handler_error("pipe()");
if(-1 == (pid = fork())){
perror("fork()");
goto ERROR;
}
if(pid == 0){
close(pip[0]); // 关闭读端
// 子进程进行 写入数据
// ...
close(pip[1]); // 关闭写端
exit(0);
}
close(pip[1]); // 关闭写端
// 父进程进行 读操作
// ...
close(pip[0]); // 关闭读端
wait(NULL); // 为子进程收尸
exit(0);
ERROR:
close(pip[0]);
close(pip[1]);
exit(1);
}
-
命名管道(半双工)
- mkfifo(3)
- 需了解,用的不多,主要因为命名管道只要进程对文件有读写权限就可以对管道文件操作,相对安全性比较低
-
SysV IPC也称为XSI IPC(本篇文章只介绍共享内存)
-
什么是Sys V IPC
- 消息队列 (message queues)
- 共享内存 (shared memory segments)
- 信号量集 ( semaphore sets)
-
命令
-
ipcs 查看当前系统所拥有的sys V IPC
-
ipcrm 删除指定的sys V ipc的机制
- 消息队列 ipcrm -q msgid
- 共享内存 ipcrm -m shmid
- 信号量 ipcrm -s semid
-
-
手册
- man 7 svipc
-
通用的特性
- 都能应用于有亲缘关系的进程和没有亲缘关系的进程
- 都是使用一个非负整型数作为其标识
- 获取实例(消息队列 共享内存 信号量)的方法都是xxxget(2)
- msgget(2)
- shmget(2)
- semget(2)
- 对于没有亲缘关系的进程都需要使用同一个key值,key的获取方法都是一样的
- ftok(3)
- 对于有亲缘关系的进程都是使用IPC_PRIVATE宏进行获取实例
- 操作函数在man手册的时候都是xxxop(2)
- man 2 msgop
- msgsnd(2) / msgrcv(2)
- man 2 shmop
- shmat(2) / shmdt(2)
- man 2 semop
- man 2 msgop
- 销毁实例都是xxxctl, 都是使用一个宏IPC_RMID
- msgctl(2)
- shmctl(2)
- semctl(2)
- 操作函数在man手册的时候都是xxxop(2)
-
共享内存 (shared memory segments)
- 进程间可以共享同一段存储空间,将这段存储空间就称为共享内存
-
如何创建
- shmget(2)
-
将共享内存与进程的虚拟地址空间映射
- shmat(2)
-
共享内存与进程的虚拟地址空间解除映射
- shmdt(2)
-
销毁共享内存
- shmctl(2)--->IPC_RMID
-