《Linux 进程间通信:消息队列、共享内存、信号量,我终于把 IPC 串起来了》
一、消息队列:进程之间传消息
msgget()
↓
msgsnd()
↓
msgrcv()
↓
msgctl()
其中:
msgget() 用来创建或者获取消息队列。
msgsnd() 用来发送消息。
msgrcv() 用来接收消息。
msgctl() 用来删除消息队列。
我自己的理解是,消息队列适合用在“进程之间传递一段数据”的场景。
比如进程 A 想告诉进程 B 一句话,或者传递一个结构体,就可以使用消息队列。
它比无名管道更灵活,因为消息可以带类型,接收方可以根据消息类型来接收指定消息。
二、共享内存:进程之间共享一块内存
共享内存是我觉得效率最高的一种 IPC 方式
它的核心思想很简单:让多个进程映射到同一块物理内存。
它的核心流程是:
shmget()
↓
shmat()
↓
读写共享内存
↓
shmdt()
↓
shmctl()
其中:
shmget() 用来创建共享内存。
shmat() 用来把共享内存挂接到当前进程。
shmdt() 用来解除挂接。
shmctl() 用来删除共享内存。
共享内存的优点是速度快,因为它不像消息队列那样频繁拷贝数据。
但是共享内存也有一个问题:多个进程同时访问同一块内存,可能会产生数据混乱。所以共享内存通常不能单独使用,往往要配合信号量。
三、信号量:控制访问共享资源的顺序
信号量不是用来传数据的。这是我一开始最容易搞混的地方。
消息队列和共享内存都和“数据”有关,而信号量主要解决的是:谁先访问,谁后访问。
比如共享内存只有一块,如果两个进程同时往里面写数据,就可能出问题。
这时候就需要信号量来控制:一个进程访问时,另一个进程先等待。
信号量的核心流程是:
semget() ↓ semctl() ↓ semop()
其中:
semget() 用来创建信号量。
semctl() 用来初始化或者删除信号量。
semop() 用来执行 P 操作和 V 操作。
我现在对 P/V 操作的理解是:
P 操作:申请资源,资源不够就等待。
V 操作:释放资源,通知别人可以用了。
所以信号量的重点不是通信,而是同步。
四、三者之间的区别
如果用一句话来区分:
消息队列:把数据发过去。
共享内存:大家一起看同一块数据。
信号量:规定谁能先访问数据。
如果用生活中的例子来理解:
消息队列像快递柜:
一个人放进去,另一个人取出来。
共享内存像公共白板:
大家都能在上面写,也都能看。
信号量像门锁:
一个人进去操作时,其他人先等。
从功能上看:
消息队列解决“传什么”。
共享内存解决“共享哪里”。
信号量解决“谁先谁后”。
五、我的学习感受
这一块刚开始学的时候确实不好理解。尤其是共享内存和信号量,如果只看函数,很容易觉得很抽象。后来我发现,学 Linux 系统编程不能只背函数,而是要先搞懂流程。
比如消息队列,我就记:
创建队列
↓
发送消息
↓
接收消息
↓
删除队列
共享内存,我就记:
创建共享内存
↓
挂接
↓
读写
↓
解除挂接
↓
删除
信号量,我就记:
创建信号量
↓
初始化
↓
P/V 操作
↓
删除
这样一来,代码就不再是零散的函数,而是一条完整的流程。
六、总结
学完消息队列、共享内存和信号量之后,我对 Linux IPC 的理解更清楚了。它们不是孤立的知识点,而是解决不同进程之间协作问题的工具。消息队列适合传递消息。共享内存适合高效共享数据。
信号量适合控制多个进程访问共享资源的顺序。
这三个知识点学完以后,我最大的收获不是记住了多少函数参数,而是开始理解 Linux 系统编程里面“进程之间如何协作”。
这也是我后面继续学习线程、网络编程和服务器开发的基础。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)