多进程/多线程并发编程,C/C++Unix/Linux应用层编程基本原理

POSIX进程间通信技术详解

POSIX IPC机制详解:消息队列、信号量与共享内存

在操作系统的多进程协作中,POSIX IPC(可移植操作系统接口进程间通信)提供了一套标准化的进程间通信机制,涵盖消息队列信号量共享内存三种核心方式。相较于传统的System V IPC,POSIX IPC具有更简洁的API设计和更高的跨平台兼容性。本文将深入解析这三种机制的系统调用及其实现细节。


一、消息队列(Message Queues)

消息队列是一种基于链表的异步通信机制,支持消息的优先级和非阻塞读写。

1. mq_open:创建或打开消息队列

#include <fcntl.h>
#include <mqueue.h>

mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);

功能:创建或打开一个消息队列。
参数
name:队列名称,以/开头且不含其他/(如/my_queue)。
oflag:标志位,常用组合:

◦ `O_RDONLY`:只读模式
◦ `O_WRONLY`:只写模式
◦ `O_RDWR`:读写模式
◦ `O_CREAT`:若不存在则创建
◦ `O_EXCL`:与`O_CREAT`联用,确保创建新队列
◦ `O_NONBLOCK`:非阻塞模式

mode:权限位(如0666),控制队列的读/写权限。
attr:指向mq_attr结构体的指针,定义队列属性:

struct mq_attr {
    long mq_flags;    // 标志(通常为0)
    long mq_maxmsg;   // 队列最大消息数
    long mq_msgsize;  // 单条消息最大长度
    long mq_curmsgs;  // 当前队列中的消息数(仅读)
};

返回值:成功返回消息队列描述符(mqd_t),失败返回-1


2. mq_send / mq_receive:发送与接收消息

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
int mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);

功能:向队列发送或从队列接收消息。
参数
mqdes:消息队列描述符。
msg_ptr:消息缓冲区指针。
msg_len:消息长度(需≤mq_msgsize)。
msg_prio:消息优先级(0最低,MQ_PRIO_MAX由系统定义)。
返回值:成功返回0mq_send)或接收的字节数(mq_receive),失败返回-1


3. mq_close / mq_unlink:关闭与删除队列

int mq_close(mqd_t mqdes);
int mq_unlink(const char *name);

功能:关闭队列描述符或删除队列实体。
参数
mqdes:待关闭的描述符。
name:待删除的队列名称。
返回值:成功返回0,失败返回-1


二、信号量(Semaphores)

信号量用于进程间的同步控制,支持二进制和计数两种类型。

1. sem_open:创建或打开命名信号量

#include <semaphore.h>

sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

功能:创建或打开一个命名信号量。
参数
name:信号量名称(格式同消息队列)。
oflag:标志位(O_CREATO_EXCL等)。
mode:权限位(如0666)。
value:信号量初始值。
返回值:成功返回信号量指针,失败返回SEM_FAILED


2. sem_init / sem_destroy:初始化与销毁匿名信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);

功能:初始化或销毁匿名信号量(仅限线程或进程内使用)。
参数
sem:信号量指针。
pshared:共享标志(0表示线程间,非0表示进程间)。
value:初始值。
返回值:成功返回0,失败返回-1


3. sem_wait / sem_post:P/V操作

int sem_wait(sem_t *sem);     // P操作(阻塞直到信号量>0)
int sem_trywait(sem_t *sem);  // 非阻塞P操作
int sem_post(sem_t *sem);     // V操作(信号量+1)

功能:执行信号量的增减操作。
参数sem:信号量指针。
返回值:成功返回0,失败返回-1


三、共享内存(Shared Memory)

共享内存允许进程直接访问同一块物理内存,是IPC中最高效的方式。

1. shm_open:创建或打开共享内存对象

#include <sys/mman.h>
#include <sys/stat.h>

int shm_open(const char *name, int oflag, mode_t mode);

功能:创建或打开共享内存对象。
参数
name:对象名称(格式同消息队列)。
oflag:标志位(O_CREATO_RDWR等)。
mode:权限位(如0666)。
返回值:成功返回文件描述符,失败返回-1


2. ftruncate:调整共享内存大小

int ftruncate(int fd, off_t length);

功能:设置共享内存对象的长度。
参数
fd:共享内存文件描述符。
length:目标长度(字节)。
返回值:成功返回0,失败返回-1


3. mmap / munmap:映射与解除映射

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);

功能:将共享内存映射到进程地址空间或解除映射。
参数
addr:映射起始地址(通常设为NULL由系统选择)。
length:映射长度。
prot:保护模式:

◦ `PROT_READ`:可读
◦ `PROT_WRITE`:可写
◦ `PROT_EXEC`:可执行
◦ `PROT_NONE`:不可访问

flags:映射标志:

◦ `MAP_SHARED`:多进程共享
◦ `MAP_PRIVATE`:私有映射(写时复制)

fd:共享内存文件描述符。
offset:文件偏移量(通常为0)。
返回值:成功返回映射地址指针(mmap)或0munmap),失败返回MAP_FAILED-1


4. shm_unlink:删除共享内存对象

int shm_unlink(const char *name);

功能:删除共享内存对象。
参数name:对象名称。
返回值:成功返回0,失败返回-1


总结

POSIX IPC通过标准化的API设计,为进程间通信提供了高效、可靠的解决方案。消息队列适用于异步任务分发,信号量用于资源同步,共享内存则适合高频数据交换。开发时应根据场景需求选择合适机制,并注意资源释放与同步问题。

回复

This is just a placeholder img.