Linux进程间通信:管道(pipe、fifo)与共享内存

622 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


操作系统中的每个进程都是独立的个体,但有时需要给他们提供一个通信的方式进行数据通信或者访问控制,因此必须能够共同访问一个相同的媒介。

操作系统提供的进程间的几种通信方式: System V标准的进程间通信方式 (另:POSIX标准)

  1. 管道 (命名管道与匿名管道)

  2. 共享内存

  3. 消息队列

  4. 信号量

进程间通信的目的

  1. 数据传输
  2. 数据共享
  3. 进程间的访问控制

因为通信的目的不同,使用场景不同,具体进程间通信方式场景: 1. 管道(命名/匿名) ---> 传输数据 2. 共享内存 ---> 共享数据 3. 消息队列 ---> 传输数据 4. 信号量 ---> 进程间的访问控制


管道

用于:进程间数据资源传输 。

原理:内核的一块缓冲区

匿名管道:pipe

需要包含头文件< unistd.h >

接口定义

int pipe(int pipefd[2]);

pipedfd: 输出型参数

  • pipefd[0] --> 从管道==读==数据

  • pipefd[1] --> 从管道==写==数据

【特性】:只能用于具有亲缘关系的进程间通信。


匿名管道的读写特性

  1. 读阻塞 若管道中没有数据,则read会阻塞,直到读到数据返回。
  2. 写阻塞 若管道中数据满了,则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作为媒介,有数据拷贝的发生。

  1. 创建或打开共享内存 | shmget
  2. 将共享内存映射到虚拟地址空间 |shmat
  3. 对共享内存进行基本内存操作 |memcpy,strcpy
  4. 解除映射关系 | shmdt
  5. 删除共享内存 | 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

共享内存命令:

  1. 查看: ipcs 选项:-m: (缩写:memory)只查看共享内存

  2. 删除: ipcrm -m <shmid>