linux学习笔记(19)进程间通讯——消息队列

消息队列

消息队列的核心特点

|-------|--------------|
| 特性 | 说明 |
| 结构化消息 | 消息有类型和内容 |
| 异步通信 | 发送和接收可以不同步 |
| 类型过滤 | 可以只接收特定类型的消息 |
| 持久化 | 消息会保留直到被读取 |

消息队列的四个核心函数

|----------|-----------|--------|
| 函数 | 作用 | 比喻 |
| msgget() | 创建/获取消息队列 | 租用邮局信箱 |
| msgsnd() | 发送消息 | 投递信件 |
| msgrcv() | 接收消息 | 收取信件 |
| msgctl() | 控制(删除等) | 退租信箱 |

例子:

cpp 复制代码
#include <stdio.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
// 定义消息结构
struct msgbuf {
    long mtype;
    char mtext[100];
};
int main() {
    int msgid;
    struct msgbuf msg;    
    // 1. 创建消息队列
    msgid = msgget(IPC_PRIVATE, 0666);
    printf("1. 创建消息队列,ID = %d\n", msgid);
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程:发送消息
        sleep(1);
        // 准备消息
        msg.mtype = 1;  // 消息类型1
        strcpy(msg.mtext, "Hello from Child!");
        // 2. 发送消息
        msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
        printf("2. 子进程发送: type=%ld, content=%s\n", msg.mtype, msg.mtext);
    } else {
        // 父进程:接收消息
        printf("3. 父进程等待接收消息...\n");
        // 3. 接收类型为1的消息
        msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
        printf("4. 父进程收到: type=%ld, content=%s\n", msg.mtype, msg.mtext);
        wait(NULL);
        // 4. 删除消息队列
        msgctl(msgid, IPC_RMID, NULL);
        printf("5. 消息队列已删除\n");
    }
    return 0;
}
cpp 复制代码
int msgid = msgget(IPC_PRIVATE, 0666);
// IPC_PRIVATE: 创建新的消息队列
// 0666: 读写权限
cpp 复制代码
struct msgbuf msg;
msg.mtype = 1;                    // 设置消息类型
strcpy(msg.mtext, "Hello");       // 设置消息内容

msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
// msgid: 消息队列ID
// &msg: 消息结构体指针
// sizeof(msg.mtext): 消息内容长度(不包括mtype)
// 0: 标志(0=阻塞)
cpp 复制代码
struct msgbuf msg;
msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
// msgid: 消息队列ID
// &msg: 接收缓冲区
// sizeof(msg.mtext): 缓冲区大小
// 1: 接收类型为1的消息(0=接收任何类型)
// 0: 标志(0=阻塞)

多类型消息:

cpp 复制代码
#include <stdio.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
struct msgbuf {
    long mtype;
    char mtext[100];
};
int main() {
    int msgid = msgget(IPC_PRIVATE, 0666);
    struct msgbuf msg;    
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程:发送多种类型的消息
        msg.mtype = 1;  // 普通消息
        strcpy(msg.mtext, "普通通知");
        msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
        msg.mtype = 10; // 紧急消息
        strcpy(msg.mtext, "紧急警报!");
        msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
        msg.mtype = 5;  // 警告消息
        strcpy(msg.mtext, "系统警告");
        msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
        printf("子进程发送了3条消息\n");
    } else {
        // 父进程:按优先级接收消息
        sleep(1);
        // 先接收紧急消息(类型10)
        msgrcv(msgid, &msg, sizeof(msg.mtext), 10, 0);
        printf收到紧急消息: %s\n", msg.mtext);
        // 再接收警告消息(类型5)
        msgrcv(msgid, &msg, sizeof(msg.mtext), 5, 0);
        printf("收到警告消息: %s\n", msg.mtext);
        // 最后接收普通消息(类型1)
        msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
        printf("收到普通消息: %s\n", msg.mtext);        
        wait(NULL);
        msgctl(msgid, IPC_RMID, NULL);
    }    
    return 0;
}

消息队列的阻塞特性

发送阻塞:

cpp 复制代码
// 如果消息队列已满,msgsnd会阻塞
msgsnd(msgid, &msg, sizeof(msg.mtext), 0);  // 阻塞直到有空间

// 非阻塞发送(队列满立即返回错误)
msgsnd(msgid, &msg, sizeof(msg.mtext), IPC_NOWAIT);

接收阻塞:

cpp 复制代码
// 如果没有消息,msgrcv会阻塞
msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);  // 阻塞直到有消息

// 非阻塞接收(没有消息立即返回)
msgrcv(msgid, &msg, sizeof(msg.mtext), 1, IPC_NOWAIT);

消息队列 vs 其他IPC

|------|--------|--------|--------|
| 特性 | 消息队列 | 管道 | 共享内存 |
| 数据结构 | 结构化消息 | 字节流 | 原始内存 |
| 同步 | 内置同步 | 需要额外同步 | 需要额外同步 |
| 持久化 | 消息持久保存 | 数据不持久 | 数据持久 |
| 复杂度 | 中等 | 简单 | 复杂 |

相关推荐
prog_61036 分钟前
【笔记】思路分享:各种大模型免费当agent后台
笔记·大语言模型·agent·cursor
神梦流17 分钟前
GE 引擎的内存优化终局:静态生命周期分析指导下的内存分配与复用策略
linux·运维·服务器
凡人叶枫19 分钟前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
凯尔萨厮23 分钟前
Maven(Windows下载安装)
笔记·maven
wdfk_prog25 分钟前
[Linux]学习笔记系列 -- [drivers][input]serio
linux·笔记·学习
xuhe241 分钟前
[全流程详细教程]Docker部署ClawBot, 使用GLM4.7, 接入TG Bot实现私人助理. 解决Docker Openclaw Permission Denied问题
linux·docker·ai·github·tldr
Lsir10110_1 小时前
【Linux】进程信号(下半)
linux·运维·服务器
酉鬼女又兒1 小时前
零基础入门Linux指南:每天一个Linux命令_pwd
linux·运维·服务器
云飞云共享云桌面1 小时前
高性能图形工作站的资源如何共享给10个SolidWorks研发设计用
linux·运维·服务器·前端·网络·数据库·人工智能
zl_dfq1 小时前
Linux 之 【多线程】(pthread_xxx、轻量级进程、原生线程库、线程ID、__thread、线程栈、线程与信号、线程与程序替换)
linux