一、消息队列:进程之间传消息

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 系统编程里面“进程之间如何协作”。

这也是我后面继续学习线程、网络编程和服务器开发的基础。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐