信号量是 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;
}

运行结果

  1. 线程 A 每隔 1 秒释放信号量,打印 "Signal sent!"

  2. 线程 B 收到信号量后点亮 LED 并延时 200ms。

  3. 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 信号量)。

运行结果

  1. 初始状态:3 个车位空闲,前 3 辆车立即停车:

    Car 1 parked! (Spaces left: 2)
    Car 2 parked! (Spaces left: 1)
    Car 3 parked! (Spaces left: 0)
  2. 车位已满:后续车辆(Car 4、Car 5)等待:

    Car 4: No space! Waiting...
    Car 5: No space! Waiting...
  3. 车辆离开:任意一辆车离开后,等待车辆抢占车位:

    text

    Car 2 left. (Spaces left: 1)
    Car 4 parked! (Spaces left: 0)
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐