Linux 进程间通信进阶:消息队列与信号量
在深入系统编程时,进程间通信(IPC)是核心话题。除了共享内存,消息队列和信号量提供了更结构化的通信与同步机制。
消息队列基础
概念与原理
消息队列是操作系统内核维护的一种 IPC 结构,不同于组件级的消息中间件。它允许进程通过一个约定的 key 值访问同一个队列。
关键点在于数据块必须带有类型标识。内核需要区分数据属于哪个进程或哪种用途,因此消息队列传输的是有类型的数据块。
在内核中,消息队列对应特定的描述结构体,包含键值和元数据。双方进程通过向队列插入节点来实现通信。
接口与命令
常用的系统调用包括创建、发送、接收和删除消息队列。
查看消息队列状态通常使用 ipcs -q 命令,而删除则需配合 ipcrm -q 指定队列 ID。
信号量机制
为什么需要信号量?
共享内存虽然高效,但缺乏保护机制。当多个进程同时读写同一块内存时,会出现并发竞争问题。信号量正是为了解决多进程访问共享资源时的并发读写冲突而设计的。
核心概念
理解信号量前,先明确几个术语:
- 共享资源:多个执行流可见的公共资源。
- 临界资源:被保护起来、一次只允许一个执行流访问的资源。
- 互斥:任何时刻只允许一个执行流访问(如 ATM 取款)。
- 同步:多个进程按特定顺序执行(如等待另一个进程完成某步)。
从程序员视角看,访问共享资源的代码段称为临界区。我们需要在进入临界区前加锁,离开时解锁。
信号量的本质
信号量本质上是一个计数器,用于衡量临界资源的数量。想象电影院售票:座位是资源,票是计数器。买票即申请资源(P 操作),离座即释放资源(V 操作)。
如果只有一个座位,初始计数为 1;若为 N 个座位,初始计数为 N。这决定了有多少进程能同时进入临界区。
接口实现
System V 信号量提供了一套完整的接口:
-
创建/获取:
semget创建信号量集或获取已存在的信号量 ID。操作系统允许创建信号量集,即一组相关的信号量。 -
控制:
semctl用于初始化、获取或删除信号量信息。例如设置初始值或查询创建时间。 -
操作:
semop对信号量进行 P/V 操作。核心数据结构是sembuf,包含三个成员:sem_num:指定操作集合中的第几个信号量。sem_op:操作值,负数表示申请(减),正数表示释放(加),0 表示等待值为 0。sem_flg:标志位,如SEM_UNDO表示进程退出时自动恢复。
下面是一个典型的信号量操作示例,展示了如何申请资源并进入临界区:
#include <sys/sem.h>
// 假设已通过 semget() 获得信号量集标识符 semid
struct sembuf sb;
sb.sem_num = ;
sb.sem_op = ;
sb.sem_flg = SEM_UNDO;
(semop(semid, &sb, ) == ) {
perror();
} {
}


