RT-Thread 信号量(Semaphore)使用详解
·
信号量是 RT-Thread 中常用的线程间同步机制,用于管理共享资源、线程同步或事件通知。RT-Thread 提供了二值信号量、计数信号量和互斥信号量(Mutex)。下面通过代码示例讲解其用法。
1. 信号量基本概念
2. 信号量 API
-
二值信号量:只有 0 和 1 两种状态,常用于线程同步(类似“事件通知”)。
-
计数信号量:允许值 ≥0,用于管理多个资源的访问(如缓冲区数量)。
-
互斥信号量(Mute)
-
RT-Thread 提供以下关键 API(需包含
<rtthread.h>):带优先级继承的二进制信号量,防止优先级反转。
| 函数 | 说明 |
|---|---|
rt_sem_init() |
静态初始化信号量 |
rt_sem_create() |
动态创建信号量 |
rt_sem_take() |
获取信号量(若不可用,线程挂起) |
rt_sem_trytake() |
尝试获取信号量(非阻塞) |
rt_sem_release() |
释放信号量 |
rt_sem_delete() |
删除动态信号量 |
rt_sem_detach() |
脱离静态信号量 |
3. 示例:二值信号量同步线程
场景
-
线程 A(生产者):定时释放信号量(模拟事件触发)。
-
线程 B(消费者):等待信号量,触发后执行任务(如点亮 LED)。
#include <rtthread.h>
#include <board.h> // 这个头文件会包含所有硬件相关的定义
#include <rtdevice.h> // 必须包含这个头文件以使用GPIO功能
#define LED_PIN GET_PIN(E, 7) // 定义LED引脚为PE7
/* 定义信号量控制块 */
static rt_sem_t sem_test = RT_NULL;
/* 线程B(消费者):等待信号量后点亮LED */
static void thread_consumer(void *param)
{
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
while (1)
{
/* 等待信号量(阻塞,超时时间 RT_WAITING_FOREVER) */
rt_sem_take(sem_test, RT_WAITING_FOREVER);
rt_pin_write(LED_PIN, PIN_HIGH); // LED亮
rt_thread_mdelay(200); // 保持200ms
rt_pin_write(LED_PIN, PIN_LOW); // LED灭
}
}
/* 线程A(生产者):每隔1秒释放信号量 */
static void thread_producer(void *param)
{
while (1)
{
rt_thread_mdelay(1000); // 延时1秒
rt_sem_release(sem_test); // 释放信号量
rt_kprintf("Signal sent!\n");
}
}
int main(void)
{
/* 动态创建信号量(初始值0,二值信号量) */
sem_test = rt_sem_create("sem_led", 0, RT_IPC_FLAG_FIFO); //RT_IPC_FLAG_FIFO表示线程等待时采用FIFO方式
if (sem_test == RT_NULL)
{
rt_kprintf("Semaphore create failed!\n");
return -1;
}
/* 创建消费者线程 */
rt_thread_t tid_consumer = rt_thread_create(
"consumer", thread_consumer, RT_NULL,
512, 20, 5);
rt_thread_startup(tid_consumer);
/* 创建生产者线程 */
rt_thread_t tid_producer = rt_thread_create(
"producer", thread_producer, RT_NULL,
512, 20, 5);
rt_thread_startup(tid_producer);
return RT_EOK;
}
运行结果
-
线程 A 每隔 1 秒释放信号量,打印
"Signal sent!"。 -
线程 B 收到信号量后点亮 LED 并延时 200ms。
-
LED 以 1Hz 频率闪烁(每次亮 200ms)。
4. 示例:计数信号量管理资源
-
模拟 3 个缓冲区的资源池,多个线程竞争使用。 比如停车位
场景描述
-
停车场共有 3 个车位(资源有限)。
-
多辆车(线程) 竞争停车位:
-
有空位时,车辆进入停车(
take信号量)。 -
无空位时,车辆等待(阻塞或超时)。
-
车辆离开时释
#include <rtthread.h> #define PARKING_SPACES 3 // 车位总数 static rt_sem_t sem_parking; // 信号量控制块 /* 车辆线程:模拟停车和离开 */ static void car_thread(void *param) { int car_id = (int)param; while (1) { /* 尝试获取车位(信号量) */ if (rt_sem_take(sem_parking, rt_tick_from_millisecond(500)) == RT_EOK) { rt_kprintf("Car %d parked! (Spaces left: %d)\n", car_id, sem_parking->value); rt_thread_mdelay(2000); // 停车2秒 rt_sem_release(sem_parking); // 离开车位 rt_kprintf("Car %d left. (Spaces left: %d)\n", car_id, sem_parking->value); } else { rt_kprintf("Car %d: No space! Waiting...\n", car_id); } rt_thread_mdelay(1000); // 每隔1秒尝试一次 } } int main(void) { /* 初始化停车位信号量(初始值=3) */ sem_parking = rt_sem_create("parking", PARKING_SPACES, RT_IPC_FLAG_FIFO); if (sem_parking == RT_NULL) { rt_kprintf("Failed to create parking semaphore!\n"); return -1; } /* 创建5辆车(线程)竞争车位 */ for (int i = 1; i <= 5; i++) { rt_thread_t tid = rt_thread_create( "car", car_thread, (void *)i, 512, 20, 5); rt_thread_startup(tid); } return RT_EOK; }放车位(
release信号量)。
-
运行结果
-
初始状态:3 个车位空闲,前 3 辆车立即停车:
Car 1 parked! (Spaces left: 2) Car 2 parked! (Spaces left: 1) Car 3 parked! (Spaces left: 0)
-
车位已满:后续车辆(Car 4、Car 5)等待:
Car 4: No space! Waiting... Car 5: No space! Waiting...
-
车辆离开:任意一辆车离开后,等待车辆抢占车位:
text
Car 2 left. (Spaces left: 1) Car 4 parked! (Spaces left: 0)
更多推荐



所有评论(0)