首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >消息队列和信号量使用情况说明

消息队列和信号量使用情况说明

作者头像
一个平凡而乐于分享的小比特
发布2026-02-02 16:04:36
发布2026-02-02 16:04:36
410
举报

🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习 🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发 ❄️作者主页:一个平凡而乐于分享的小比特的个人主页 ✨收录专栏:UCOS-III,本专栏为UCOS-III学习记录 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

消息队列和信号量使用情况说明

核心原则

信号量:用于同步和资源计数(关心"有没有") 消息队列:用于数据传输(关心"是什么")

使用信号量的场景

1.资源保护(互斥锁)
代码语言:javascript
复制
OS_SEM mutex_sem;

void task1(void *p_arg) {
    OSSemPend(&mutex_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
    // 访问共享资源(如全局变量、外设)
    OSSemPost(&mutex_sem, OS_OPT_POST_1, &err);
}

void task2(void *p_arg) {
    OSSemPend(&mutex_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
    // 访问同一共享资源
    OSSemPost(&mutex_sem, OS_OPT_POST_1, &err);
}

特点:只关心资源是否被占用,不传输数据

2.任务同步
代码语言:javascript
复制
OS_SEM sync_sem;

// 任务A完成工作后通知任务B
void task_a(void *p_arg) {
    // 完成某些工作
    OSSemPost(&sync_sem, OS_OPT_POST_1, &err);  // 通知任务B
}

void task_b(void *p_arg) {
    OSSemPend(&sync_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
    // 收到通知后开始工作
}

特点:只关心事件是否发生,不传递具体信息

3. 资源池管理
代码语言:javascript
复制
OS_SEM resource_sem;

void init(void) {
    OSSemCreate(&resource_sem, "Buffer Pool", 5, &err);  // 5个缓冲区
}

void consumer_task(void *p_arg) {
    OSSemPend(&resource_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
    // 获取到一个缓冲区,可以使用了
    // 使用完后...
    OSSemPost(&resource_sem, OS_OPT_POST_1, &err);
}

特点:只关心可用资源数量

使用消息队列的场景

1. 数据传输
代码语言:javascript
复制
OS_Q data_queue;

typedef struct {
    uint8_t sensor_id;
    float   value;
    uint32_t timestamp;
} sensor_data_t;

void sensor_task(void *p_arg) {
    sensor_data_t data;
    data.sensor_id = 1;
    data.value = Read_Sensor();
    data.timestamp = OSTimeGet();
    
    OSQPost(&data_queue, &data, sizeof(data), OS_OPT_POST_FIFO, &err);
}

void process_task(void *p_arg) {
    sensor_data_t *p_data;
    OS_MSG_SIZE size;
    
    p_data = OSQPend(&data_queue, 0, OS_OPT_PEND_BLOCKING, &size, 0, &err);
    // 处理具体的传感器数据
    printf("Sensor %d: %.2f at %lu\n", p_data->sensor_id, p_data->value, p_data->timestamp);
}

特点:需要传递具体的数据内容

2. 命令/指令传递
代码语言:javascript
复制
OS_Q cmd_queue;

typedef enum {
    CMD_START,
    CMD_STOP, 
    CMD_SET_SPEED,
    CMD_GET_STATUS
} command_t;

void ui_task(void *p_arg) {
    command_t cmd = CMD_SET_SPEED;
    int speed = 100;
    
    // 发送命令和参数
    OSQPost(&cmd_queue, &cmd, sizeof(cmd), OS_OPT_POST_FIFO, &err);
}

void motor_task(void *p_arg) {
    command_t *p_cmd;
    OS_MSG_SIZE size;
    
    p_cmd = OSQPend(&cmd_queue, 0, OS_OPT_PEND_BLOCKING, &size, 0, &err);
    switch(*p_cmd) {
        case CMD_SET_SPEED:
            // 设置电机速度
            break;
        // 处理其他命令...
    }
}

特点:需要传递具体的命令和参数

3. 数据流处理
代码语言:javascript
复制
OS_Q audio_queue;

void adc_task(void *p_arg) {
    int16_t audio_buffer[128];
    // 采集音频数据
    OSQPost(&audio_queue, audio_buffer, sizeof(audio_buffer), OS_OPT_POST_FIFO, &err);
}

void audio_process_task(void *p_arg) {
    int16_t *p_audio_data;
    OS_MSG_SIZE size;
    
    p_audio_data = OSQPend(&audio_queue, 0, OS_OPT_PEND_BLOCKING, &size, 0, &err);
    // 对音频数据进行处理(滤波、编码等)
}

特点:需要传递大量的数据块

实际项目中的选择指南

选择信号量的情况

当你只需要回答这些问题时:

  • “资源可用吗?” ✅ 信号量
  • “事件发生了吗?” ✅ 信号量
  • “有几个资源可用?” ✅ 计数信号量
  • “可以进入临界区吗?” ✅ 互斥信号量
选择消息队列的情况

当你需要回答这些问题时:

  • “数据是什么?” ✅ 消息队列
  • “命令是什么?参数是多少?” ✅ 消息队列
  • “传感器读数是多少?” ✅ 消息队列
  • “要显示什么文本?” ✅ 消息队列

混合使用示例

实际项目中经常组合使用:

代码语言:javascript
复制
OS_SEM data_ready_sem;  // 数据就绪信号量
OS_Q   sensor_data_q;   // 传感器数据队列

void sensor_task(void *p_arg) {
    sensor_data_t data;
    
    while(1) {
        data = Read_Sensor();
        OSQPost(&sensor_data_q, &data, sizeof(data), OS_OPT_POST_FIFO, &err);
        OSSemPost(&data_ready_sem, OS_OPT_POST_1, &err);  // 通知有数据
        OSTimeDly(100, OS_OPT_TIME_DLY, &err);
    }
}

void display_task(void *p_arg) {
    sensor_data_t *p_data;
    OS_MSG_SIZE size;
    
    while(1) {
        OSSemPend(&data_ready_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
        p_data = OSQPend(&sensor_data_q, 0, OS_OPT_PEND_BLOCKING, &size, 0, &err);
        LCD_Display(*p_data);
    }
}

总结

简单决策树:

代码语言:javascript
复制
要传递具体数据吗?
├── 是 → 使用消息队列
└── 否 → 
    只需要同步或资源管理吗?
    ├── 是 → 使用信号量
    └── 否 → 可能需要两者结合

记住:

  • 信号量:轻量级的同步工具
  • 消息队列:功能更强大的数据传输工具
  • 在性能敏感的场景,能用信号量解决的问题不要用消息队列
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 消息队列和信号量使用情况说明
    • 核心原则
    • 使用信号量的场景
      • 1.资源保护(互斥锁)
      • 2.任务同步
      • 3. 资源池管理
    • 使用消息队列的场景
      • 1. 数据传输
      • 2. 命令/指令传递
      • 3. 数据流处理
    • 实际项目中的选择指南
      • 选择信号量的情况
      • 选择消息队列的情况
    • 混合使用示例
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档