一、进程间通信
进程间通信就是不同进程之间交换数据的过程。因为每个进程都有自己独立的虚拟地址空间,一个进程不能直接访问另一个进程的内存,所以必须通过操作系统提供的机制来进行通信。管道(Pipe)和命名管道(FIFO)
信号(Signal)
共享内存(Shared Memory)
消息队列(Message Queue)
信号量(Semaphore)
套接字(Socket)
二、管道(Pipe)
管道是 Linux 中最古老、最简单的进程间通信方式,用于有亲缘关系的进程之间(比如父子进程、兄弟进程)的通信。1. 管道的特点
半双工通信:数据只能在一个方向上流动,要么从父进程流向子进程,要么从子进程流向父进程
只能用于有亲缘关系的进程之间
数据一旦被读出,就从管道中消失了
管道的大小是有限的,默认是 4KB
2. pipe 函数:创建管道
pipefd:输出参数,返回两个文件描述符
返回值:成功返回 0,失败返回 - 1
3. 管道的工作原理
pipe 函数创建一个管道,返回两个文件描述符。父进程 fork 出子进程后,父子进程都拥有这两个文件描述符。如果我们要实现父进程写、子进程读,那么父进程需要关闭 pipefd [0],子进程需要关闭 pipefd [1]。示例:父子进程通过管道通信
三、管道的读写特性
1. 读管道
如果管道的写端已经关闭,那么 read 会返回 0,表示读到了文件末尾
如果管道的写端没有关闭,并且管道中没有数据,那么 read 会阻塞,直到有数据可读
如果管道中有数据,那么 read 会立即返回实际读到的字节数
2. 写管道
如果管道的读端已经关闭,那么写操作会导致进程收到 SIGPIPE 信号,默认动作是终止进程
如果管道的读端没有关闭,并且管道已满,那么 write 会阻塞,直到有空间可写
如果管道有空间,那么 write 会立即返回实际写入的字节数
四、命名管道(FIFO)
管道只能用于有亲缘关系的进程之间,而命名管道(也叫 FIFO)可以用于任意两个进程之间的通信。命名管道是一种特殊类型的文件,它在文件系统中有一个对应的路径名。不同的进程可以通过打开这个文件来进行通信。1. 创建命名管道
方法一:用 mkfifo 命令创建
执行这个命令后,当前目录下会出现一个名为 myfifo 的文件,类型是 p。方法二:用 mkfifo 函数创建
pathname:命名管道的路径名
mode:文件权限,比如 0644
返回值:成功返回 0,失败返回 - 1
2. 命名管道的使用
命名管道的使用和普通文件一样,用 open 打开,用 read 和 write 读写,用 close 关闭。写端程序:fifo_write.c
3. 运行测试
编译两个程序:
注意:打开命名管道时,读端和写端会互相等待。如果只有读端打开,那么 open 会阻塞,直到有写端打开;反之亦然。五、实战:用管道实现简单的进程间聊天程序
编译运行这个程序,就可以在父进程和子进程之间互相发送消息了。六、总结
这一期我们学习了 Linux 进程间通信的两种方式:管道(Pipe):用于有亲缘关系的进程之间的半双工通信pipe 函数:创建管道,返回两个文件描述符管道的读写特性:阻塞、EOF 等命名管道(FIFO):用于任意进程之间的通信mkfifo 命令和函数:创建命名管道命名管道的使用:和普通文件一样打开、读写、关闭实战:用两个管道实现全双工的父子进程聊天程序下一期讲更高效的进程间通信方式:共享内存和消息队列。大家有任何不懂的地方,或者敲代码遇到了 bug,都可以在评论区留言,我都会一一回复。如果这篇内容对你有帮助,别忘了点赞、在看、转发给身边同样在学 C 语言的朋友。