
摘要:本课讲解 Zephyr RTOS 中 Message Queue(消息队列)的核心价值——既能同步线程,又能传递数据。通过 UART 接收字符示例,对比 Semaphore 只能同步、无法传数据的局限,并深入介绍 k_msgq 的 FIFO 特性、常用 API(K_MSGQ_DEFINE / k_msgq_put / k_msgq_get)与 Producer-Consumer 实战代码,助你掌握 Zephyr 线程通信的进阶用法。Zephyr RTOS 消息队列实战:从 Semaphore 到 k_msgq 的进阶本章目标完成后,你应该能够回答:什么时候使用 Message Queue,而不是 Semaphore 或 Mutex?并且能够熟练使用k_msgq实现线程之间的数据通信。一、为什么需要 Message Queue?前面已经学习:Thread ↓ Semaphore ↓ Mutex它们都是同步(Synchronization)。但是很多时候:线程 A 不仅要通知线程 B还要告诉它:“这是我要发送的数据”例如:UART接收到一个字符'A'需要发送给另一个线程。如果 Semaphore:UART Thread ↓ k_sem_give()Worker Threadk_sem_take()Worker 知道:有数据来了但是:数据在哪?必须再共享变量:charrx_char;例如:rx_char='A';k_sem_give();Worker:k_sem_take();printf("%c", rx_char);问题来了:如果 UART 很快:A B C共享变量变成:rx_char='C'A、B全部丢失。实战:UART 接收字符 → 消息队列 → 工作线程下面是一个完整的main.c,演示 UART 轮询读取字符,通过k_msgq_put()发送到消息队列,工作线程用k_msgq_get()接收并打印:#includezephyr/kernel.h#includezephyr/sys/printk.h#includezephyr/device.h#includezephyr/drivers/uart.h/* 定义消息队列:每个元素 1 字节(char),最多缓存 10 个字符 */K_MSGQ_DEFINE(uart_msgq,sizeof(char),10,4);#defineSTACK_SIZE1024#definePRIORITY5K_THREAD_STACK_DEFINE(worker_stack,STACK_SIZE);structk_threadworker_thread;/* 工作线程:从消息队列接收字符并打印 */voidworker(void*a,void*b,void*c){charrx_char;while(1){/* 阻塞等待,直到队列中有数据 */k_msgq_get(uart_msgq,rx_char,K_FOREVER);printk("Worker received: %c\n",rx_char);}}intmain(void){conststructdevice*uart_dev;charrx_char;/* 获取 UART 设备(以 UART0 为例) */uart_dev=DEVICE_DT_GET(DT_NODELABEL(uart0));if(!device_is_ready(uart_dev)