本文已参与「新人创作礼」活动,一起开启掘金创作之路。
操作系统中的每个进程都是独立的个体,但有时需要给他们提供一个通信的方式进行数据通信或者访问控制,因此必须能够共同访问一个相同的媒介。
操作系统提供的进程间的几种通信方式:
System V标准的进程间通信方式 (另:POSIX标准)
-
管道 (命名管道与匿名管道)
-
共享内存
-
消息队列
-
信号量
进程间通信的目的:
- 数据传输
- 数据共享
- 进程间的访问控制
因为通信的目的不同,使用场景不同,具体进程间通信方式场景: 1. 管道(命名/匿名) --->
传输数据2. 共享内存 --->共享数据3. 消息队列 --->传输数据4. 信号量 --->进程间的访问控制
管道
用于:进程间数据资源传输 。
原理:内核的一块缓冲区
匿名管道:pipe
需要包含头文件
< unistd.h >
接口定义:
int pipe(int pipefd[2]);
pipedfd: 输出型参数
-
pipefd[0]--> 从管道==读==数据 -
pipefd[1]--> 从管道==写==数据
【特性】:只能用于具有亲缘关系的进程间通信。
匿名管道的读写特性
- 读阻塞
若管道中没有数据,则
read会阻塞,直到读到数据返回。 - 写阻塞
若管道中数据满了,则
write会阻塞,直到数据被读取,管道中有空闲位置,写入数据后返回。
若管道所有的读端都被关闭,则write会触发异常(SIGPIPE),通知用户无人读了,导致进程退出。
若管道所有的写端都被关闭,则read读完管道数据后,返回0(通知用户无人写了)
管道自带同步与互斥特性:当读写大小小于PIPE_BUF时,保证操作原子性。
操作原子性:操作不可被打断。
- 互斥:保证对临界资源同一时间的唯一访问性。(临界资源:大家都能访问到的公共资源,如全局变量等)
- 同步:保证对临界资源访问的时序可控性,以求公平合理。
管道为半双工通信:可选择方向的单向通信。管道生命周期随进程。
ps -ef | grep ssh
ps -ef:输出:所有的进程信息,写入标准输出
grep ssh 从标准输入读取数据,进行过滤处理
命名管道:fifo
命名管道可见于文件系统。
因为创建命名管道会随之在文件系统中创建一个命名管道文件(p类型文件),所有进程都能够通过打开管道文件,进而获取管道的操作句柄,因此命名管道可以用于同一主机上任何进程间通信。
管道的原理依然还是内核的缓冲区。只是通过文件向所有进程都提供了能够访问管道的方法。
mkfifo接口: (3号man手册)
int mkfifo(const char *pathname,mode_t mode);
-
pathname:管道文件名。 -
mode:创建权限。 -
返回值:成功返回
0,失败返回-1。
命名管道文件的打开特性
- 若管道没有以写的方式打开,这时如果只读打开,则会阻塞,直到文件被以写的方式打开为止。
(以
只读方式打开时,若管道文件没有其他进程以写的方式打开,则阻塞) - 若管道没有以读的方式打开,这时如果只写打开,则会阻塞,直到文件被以读的方式打开为止。
- 若管道以读写方式打开,则不会阻塞。
读写特性
与匿名管道相同。
共享内存
共享内存是==最快==的进程间通信方式,没有之一!
因为相较于其他进程间通信方式,共享内存直接将一块内存映射到虚拟地址空间 / 用户空间,用户可以直接通过地址对内存进行操作,并反馈到其他进程,少了两步(用户态 <-> 内核态)的数据拷贝的过程。
管道:有一个
buf作为媒介,有数据拷贝的发生。
- 创建或打开共享内存 |
shmget - 将共享内存映射到虚拟地址空间 |
shmat - 对共享内存进行基本内存操作 |
memcpy,strcpy等 - 解除映射关系 |
shmdt - 删除共享内存 |
shmctl
接口:
int shmget(ket_t key,size_t size,int shmflg,mode_flags);
key:共享内存标识符。size:共享内存大小。shmflg:打开方式/创建权限。IPC_CREAT:共享内存不存在则创建,存在则打开。IPC_EXCL:与IPC_CREATE同用,若不存在则创建,存在则报错。mode_flags:权限。- 返回值:成功返回操作句柄
shmid,失败返回-1。
共享内存命令:
-
查看:
ipcs选项:-m: (缩写:memory)只查看共享内存。 -
删除:
ipcrm -m <shmid>