0

0

【Linux】system V消息队列,信号量

絕刀狂花

絕刀狂花

发布时间:2025-04-17 13:24:20

|

1031人浏览过

|

来源于php中文网

原创

01.消息队列

消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

【Linux】system V消息队列,信号量

发送方将消息放入队列,接收方从队列中取出消息

发送方和接收方不需要同时在线,消息可以存储在队列中,等待接收方处理

消息队列也有自己的属性

代码语言:javascript代码运行次数:0运行复制
struct msqid_ds{    struct ipc_perm msg_perm; /* Ownership and permissions */    time_t msg_stime;         /* Time of last msgsnd(2) */    time_t msg_rtime;         /* Time of last msgrcv(2) */    time_t msg_ctime;         /* Time of creation or last                                 modification by msgctl() */    unsigned long msg_cbytes; /* # of bytes in queue */    msgqnum_t msg_qnum;       /* # number of messages in queue */    msglen_t msg_qbytes;      /* Maximum # of bytes in queue */    pid_t msg_lspid;          /* PID of last msgsnd(2) */    pid_t msg_lrpid;          /* PID of last msgrcv(2) */};
【Linux】system V消息队列,信号量

System V 消息队列接口

System V 消息队列是 UNIX 系统提供的一种 IPC 机制,主要接口包括:

(1) ftok • 功能:生成消息队列的键值(key_t)。 • 原型:

代码语言:javascript代码运行次数:0运行复制
key_t ftok(const char *pathname, int proj_id);

• 参数: • pathname:文件路径。 • proj_id:项目 ID。 • 返回值:生成的键值。

(2) msgget • 功能:创建或获取消息队列。 • 原型:

代码语言:javascript代码运行次数:0运行复制
int msgget(key_t key, int msgflg);

• 参数: • key:消息队列的键值。 • msgflg:标志位(如 IPC_CREATIPC_EXCL)。 • 返回值:消息队列的标识符(msqid)。

(3) msgsnd • 功能:向消息队列发送消息。 • 原型:

代码语言:javascript代码运行次数:0运行复制
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

• 参数: • msqid:消息队列标识符。 • msgp:指向消息结构的指针。 • msgsz:消息的大小。 • msgflg:标志位(如 IPC_NOWAIT)。

消息结构通常定义如下:

代码语言:javascript代码运行次数:0运行复制
struct Message {    long mtype;       // 消息类型(必须为 long 类型)    char mtext[100];  // 消息内容(可以是任意类型)};

消息类型必须为 long 类型 消息内容,可以是字符数组、结构体等

(4) msgrcv • 功能:从消息队列接收消息。 • 原型:

代码语言:javascript代码运行次数:0运行复制
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

• 参数: • msqid:消息队列标识符。 • msgp:指向消息结构的指针。 • msgsz:消息的大小。 • msgtyp:消息类型。 • msgflg:标志位(如 IPC_NOWAIT)。

(5) msgctl • 功能:控制消息队列(如删除队列、获取状态等)。 • 原型:

代码语言:javascript代码运行次数:0运行复制
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

• 参数: • msqid:消息队列标识符。 • cmd:控制命令(如 IPC_RMIDIPC_STAT)。 • buf:指向 msqid_ds 结构的指针。


代码语言:javascript代码运行次数:0运行复制
dyx@dyx-VMware-Virtual-Platform:~/bitcode$ ipcs--------- 消息队列 -----------键        msqid      拥有者  权限     已用字节数 消息      ------------ 共享内存段 --------------键        shmid      拥有者  权限     字节     连接数  状态      --------- 信号量数组 -----------键        semid      拥有者  权限     nsems     
02.信号量

首先进行几个概念的理解:

多个执行流(进程),能看到的一份资源:共享资源被保护起来的共享资源 - 临界资源 —同步和互斥来保护互斥:任何时刻只能有一个进程在访问共享资源资源被访问,朴素的认识就是通过代码访问—代码=访问共享资源的代码+不访问共享资源的代码临界区是指访问临界资源的代码段。在临界区内,线程或进程会访问或修改共享资源
【Linux】system V消息队列,信号量
代码语言:javascript代码运行次数:0运行复制
#include std::mutex mtx;int shared_variable = 0;void increment() {    mtx.lock(); // 加锁    shared_variable++; // 临界区    mtx.unlock(); // 解锁}

信号量是用来保护共享资源,实现资源的互斥访问,信号量的核心思想是通过一个计数器来管理资源的可用数量

申请信号量的本质就是对资源的预定机制

它通过 原子操作 来控制资源的分配和释放,确保多个线程或进程能够安全地访问共享资源。信号量的核心思想是:

计数器: • 信号量维护一个非负整数计数器,表示当前可用资源的数量。 • 当计数器大于 0 时,表示资源可用;当计数器为 0 时,表示资源不可用。 原子操作: • 信号量的操作(P 操作和 V 操作)是原子的,即这些操作在执行过程中不会被中断。 • 原子性确保了多个线程或进程在访问信号量时不会发生竞争条件。 阻塞与唤醒: • 当线程或进程请求资源时(P 操作),如果计数器为 0,则线程或进程会被阻塞,直到资源可用。 • 当线程或进程释放资源时(V 操作),如果有等待的线程或进程,则唤醒其中一个。

信号量与共享资源之间的交互通过 P 操作 和 V 操作 实现。以下是信号量与共享资源的交互过程:

P 操作(Wait 或 Acquire) • 功能:请求资源。 • 实现: • 计数器减 1。 • 如果计数器小于 0,则当前线程或进程被阻塞,直到计数器大于 0。 • 伪代码:代码语言:javascript代码运行次数:0运行复制
P(semaphore):    semaphore--    if semaphore < 0:        block()
V 操作(Signal 或 Release) • 功能:释放资源。 • 实现: • 计数器加 1。 • 如果有等待的线程或进程,则唤醒其中一个。 • 伪代码:代码语言:javascript代码运行次数:0运行复制
V(semaphore):    semaphore++    if semaphore <= 0:        wakeup()

假设有一个共享资源(如打印机),使用信号量来管理其访问:

Tago AI
Tago AI

AI生成带货视频,专为电商卖货而生

下载

初始化信号量: • 信号量计数器初始化为 1(表示资源可用)。

代码语言:javascript代码运行次数:0运行复制
semaphore = 1;

线程 A 请求资源: • 执行 P 操作,计数器减 1。 • 计数器变为 0,资源被线程 A 占用。

代码语言:javascript代码运行次数:0运行复制
P(semaphore); // semaphore = 0

线程 B 请求资源: • 执行 P 操作,计数器减 1。 • 计数器变为 -1,线程 B 被阻塞。

代码语言:javascript代码运行次数:0运行复制
P(semaphore); // semaphore = -1

线程 A 释放资源: • 执行 V 操作,计数器加 1。 • 计数器变为 0,唤醒线程 B。

代码语言:javascript代码运行次数:0运行复制
V(semaphore); // semaphore = 0

线程 B 占用资源: • 线程 B 被唤醒,占用资源。 • 计数器仍为 0,表示资源被线程 B 占用。

线程 B 释放资源: • 执行 V 操作,计数器加 1。 • 计数器变为 1,资源可用。

代码语言:javascript代码运行次数:0运行复制
V(semaphore); // semaphore = 1

和共享内存,消息队列一样,必须先让不同的进程看到同一个计数器

意味着信号量也是一个公共资源

System V 信号量接口

(1) semget • 功能:创建或获取信号量集。 • 原型:

代码语言:javascript代码运行次数:0运行复制
int semget(key_t key, int nsems, int semflg);

• 参数: • key:信号量集的键值。 • nsems:信号量集中的信号量数量。 • semflg:标志位(如 IPC_CREATIPC_EXCL)。 • 返回值:成功返回信号量集的标识符,失败返回 -1。

(2) semop • 功能:执行信号量操作(P 操作或 V 操作)。 • 原型:

代码语言:javascript代码运行次数:0运行复制
int semop(int semid, struct sembuf *sops, size_t nsops);

• 参数: • semid:信号量集的标识符。 • sops:指向 sembuf 结构数组的指针。 • nsops:操作的数量。 • 返回值:成功返回 0,失败返回 -1。

(3) semctl • 功能:控制信号量集(如初始化、删除、获取状态等)。 • 原型:

代码语言:javascript代码运行次数:0运行复制
int semctl(int semid, int semnum, int cmd, ...);

• 参数: • semid:信号量集的标识符。 • semnum:信号量的索引。 • cmd:控制命令(如 IPC_RMIDSETVAL)。 • ...:可选参数,通常是一个 union semun 结构。 • 返回值:成功返回 0 或其他值(取决于 cmd),失败返回 -1。


示例:

代码语言:javascript代码运行次数:0运行复制
#include #include #include int main() {    key_t key = ftok("semfile", 65);    int semid = semget(key, 1, 0666 | IPC_CREAT);    // 初始化信号量值为 1    semctl(semid, 0, SETVAL, 1);    struct sembuf sb;    sb.sem_num = 0;    sb.sem_op = -1; // P 操作    sb.sem_flg = 0;    semop(semid, &sb, 1);    std::cout << "Critical section" << std::endl;    sb.sem_op = 1; // V 操作    semop(semid, &sb, 1);    // 删除信号量    semctl(semid, 0, IPC_RMID);    return 0;}

【Linux】system V消息队列,信号量
03.OS对system V ipc的管理

不管是共享内存,消息队列还是信号量,他们调用接口都为xxxget,xxxctl

IPC 标识符 操作系统为每个 IPC 资源分配一个唯一的 标识符(ID),用于标识和管理该资源。标识符的类型包括: • 消息队列标识符(msqid):用于标识消息队列。 • 共享内存标识符(shmid):用于标识共享内存段。 • 信号量标识符(semid):用于标识信号量集。

标识符的生成方式: • 通过 ftok 函数生成键值(key_t),然后使用 msggetshmgetsemget 创建或获取 IPC 资源。


资源管理结构 操作系统为每种 IPC 资源维护一个 管理结构,用于存储资源的属性和状态。以下是常见的管理结构:消息队列管理结构

msqid_ds: • 存储消息队列的属性,如权限、消息数量、最后操作时间等。 • 示例:

代码语言:javascript代码运行次数:0运行复制
```cppstruct msqid_ds {    struct ipc_perm msg_perm; // 权限信息    time_t msg_stime;        // 最后发送时间    time_t msg_rtime;        // 最后接收时间    time_t msg_ctime;        // 最后修改时间    unsigned long msg_cbytes; // 当前字节数    msgqnum_t msg_qnum;      // 当前消息数量    msglen_t msg_qbytes;     // 最大字节数    pid_t msg_lspid;         // 最后发送进程的 PID    pid_t msg_lrpid;         // 最后接收进程的 PID};```
共享内存管理结构

shmid_ds: • 存储共享内存段的属性,如大小、权限、附加进程数等。 • 示例:

代码语言:javascript代码运行次数:0运行复制
```cppstruct shmid_ds {    struct ipc_perm shm_perm; // 权限信息    size_t shm_segsz;        // 共享内存大小    time_t shm_atime;        // 最后附加时间    time_t shm_dtime;        // 最后分离时间    time_t shm_ctime;        // 最后修改时间    pid_t shm_cpid;          // 创建进程的 PID    pid_t shm_lpid;          // 最后操作进程的 PID    shmatt_t shm_nattch;     // 当前附加进程数};```
信号量管理结构

semid_ds: • 存储信号量集的属性,如权限、信号量数量、最后操作时间等。 • 示例:

代码语言:javascript代码运行次数:0运行复制
```cppstruct semid_ds {    struct ipc_perm sem_perm; // 权限信息    time_t sem_otime;        // 最后操作时间    time_t sem_ctime;        // 最后修改时间    unsigned short sem_nsems; // 信号量数量};```

资源权限 每种 IPC 资源都有一个 权限结构(ipc_perm),用于控制资源的访问权限。权限结构包括: • 所有者用户 ID(uid):资源的所有者。 • 所有者组 ID(gid):资源的所有者组。 • 创建者用户 ID(cuid):资源的创建者。 • 创建者组 ID(cgid):资源的创建者组。 • 权限模式(mode):资源的访问权限(如读、写、执行)。

资源生命周期 IPC 资源的生命周期包括:创建:通过 msggetshmgetsemget 创建资源。使用:进程通过标识符访问资源。修改:通过 msgctlshmctlsemctl 修改资源属性。删除:通过 msgctlshmctlsemctl 删除资源。

操作系统维护一个 ​全局的 IPC 资源表,用于存储所有 IPC 资源的信息。每种 IPC 资源(消息队列、共享内存、信号量)都有自己的资源表,表中的每一项对应一个具体的 IPC 资源

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

183

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

287

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

258

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

124

2025.08.07

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

220

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

192

2025.07.04

c语言union的用法
c语言union的用法

c语言union的用法是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型,union的使用可以帮助我们节省内存空间,并且可以方便地在不同的数据类型之间进行转换。使用union时需要注意对应的成员是有效的,并且只能同时访问一个成员。本专题为大家提供union相关的文章、下载、课程内容,供大家免费下载体验。

126

2023.09.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1130

2023.10.19

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

15

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

Swoft2.x速学之http api篇课程
Swoft2.x速学之http api篇课程

共16课时 | 0.9万人学习

PHP入门到实战消息队列RabbitMQ
PHP入门到实战消息队列RabbitMQ

共22课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号