Linux进程间通信,大致有五种
原始的信号和管道,还有共享内存,消息队列和信号。
1. 管道
管道分为两种 pipe和fifo
pipe可用有亲缘关系的进程,比如父子进程,兄弟进程
fifo可用不同进程之间,不限于亲缘关系
pipe
半双工,一端读一端写,数据在一个方向上流动。可以看成是一种特殊的文件,只不过它只在内存里,不落地到文件系统。
管道的缓冲区有限制,PIPE_BUF 一般是一个页面的大小,管道传输的无格式字节流,这就要求读写双发要实现约定好数据格式。它没有名字,所以只能在亲缘关系进程之间使用。
fifo
一种特殊文件,落地到文件系统。严格支持先进先出。
int mkfifo(const char * pathname, mode_t mode)
2. 信号
信号,一个进程向另一个进程发送很简短的信号,通知某个事情。
信号在signal.h中有定义,SIG开头的都是信号。
这里要重点掌握两个函数
- signal
- sigaction 专业
sigaction的优势在于,在调用它之前,可以设置信号屏蔽字可以防止信号在它的处理函数还未运行结束时就被接收到的情况。
还有两个发送信号的函数 - kill
- alarm
3. 共享内存
共享内存,可以允许两个以上的进程同时访问一个块内存。这个内存实际上是在内核态中的,进程使用时,会映射到进程的地址空间中。
主要函数
- shmget 创建或者打开共享内存
int shmget(key_t key, size_t size, int shmflg); - shmat 把共享内存映射过来
void *shmat(int shm_id, const void *shm_addr, int shmflg); - 解除映射
int shmdt(const void *shmaddr); - 控制共享内存
int shmctl(int shm_id, int command, struct shmid_ds *buf);
命令选项
IPC_STAT 设置共享内存访问权限
IPC_SET 设置共享内存访问权限
IPC_RMID 删除共享内存
4. 消息队列
消息队列,是消息的链表,存放再内核中,有一个标识符(队列id)标记(其实就是ipc id, 这里ipc指的是system v ipc ,其实共享内存和信号也都有这个id)。
写权限的进程可以往消息队列中添加消息
具有读权限的进程可以从消息队列中读取信息。
又因为它在内核中,所以多进程之间可以访问,在进程结束时,消息队列不会被清除。
可按照类型随机查询,并不一定要按先进先出的次序读取。
消息: 定长消息头+变长消息正文
- msgget//创建或者打开一个消息队列
- msgsnd
- int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz, long
mtype,
int msgflg )
mtype 如果mtype 的值是零的话,函数将不做类型检查而自动返回队列中的最早的消息 - msgctl //操作消息队列
5. 信号量
信号量其实有点不同,是用来保持进程之间互斥和同步,而不是共享数据的。它提供一种访问机制,让一个临界区只能由x个进程来访问。它是一种特殊的变量,程序对其访问都是原子操作,由两种操作,一种时等待P,另一种时发送V
- P(sv): 当sv>0时,sv-1,向下执行;当sv=0时,挂起
- V(sv): 当系统由因为等待sv而挂起的进程时,使其执行;如果没有,sv+1
信号量三个函数
- semget 打开和创建一个信号量
- semop 信号量P V操作
- semctl 信号量初始化,删除操作