FreeRTOS信号量实战:停车场管理
信号量是 FreeRTOS 中实现任务同步和资源管理的重要工具。下面通过一个 停车场车位管理 的例子,来理解计数信号量的工作原理和使用方法。一个拥有 5个车位 的小型停车场,多辆汽车(任务)需要进出停车场,必须确保不会让超过5辆车同时进入(不发生“溢出”)。计数信号量正是管理此类“多个同类资源”的绝佳选择。
1. 系统初始化:创建信号量
首先,在程序开始时创建一个计数信号量,用它来表示空闲车位的数量。
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"// 定义停车场最大容量和信号量句柄
#define PARKING_CAPACITY 5
SemaphoreHandle_t xParkingSpacesSemaphore;void main( void )
{// 硬件初始化biosinit();// 创建计数信号量,初始值和最大值均为停车场容量xParkingSpacesSemaphore = xSemaphoreCreateCounting( PARKING_CAPACITY, PARKING_CAPACITY );if( xParkingSpacesSemaphore != NULL ) {// 信号量创建成功,创建代表多辆车的任务xTaskCreate( vCarEnterTask, "CarEnter", 256, NULL, 1, NULL );xTaskCreate( vCarExitTask, "CarExit", 256, NULL, 1, NULL );vTaskStartScheduler();}while(1);
}2. 车辆入场任务:获取信号量(占用车位)
当一辆车想要进入停车场时,它必须尝试“获取”一个信号量。这相当于查看并占用一个空闲车位。
void vCarEnterTask( void *pvParameters )
{int car_id = (int)pvParameters; // 假设每辆车有唯一IDwhile(1) {// 模拟随机到达间隔vTaskDelay( pdMS_TO_TICKS( (rand() % 3000) + 1000 ) );// 尝试获取信号量(等待一个空闲车位),最多等待10秒if( xSemaphoreTake( xParkingSpacesSemaphore, pdMS_TO_TICKS(10000) ) == pdTRUE ) {// 成功获取信号量,意味着占到一个车位log("Car %d: Found a space! Entering parking lot. Spaces left: %d\n", car_id, uxSemaphoreGetCount(xParkingSpacesSemaphore) );// 车辆在停车场内停留一段时间vTaskDelay( pdMS_TO_TICKS( (rand() % 10000) + 5000 ) );// 停留结束后,车辆准备离开,通过任务通知等方式告知出口任务// ... (例如: xTaskNotifyGive(xExitTaskHandle)) ...} else {// 等待5秒后仍未等到车位,选择离开log("Car %d: Waited 5 seconds, no space found. Driving away...\n", car_id);}}
}3. 车辆离场任务:释放信号量(释放车位)
当一辆车离开停车场时,它需要“释放”信号量,表示一个车位被空出,可供后续车辆使用。
void vCarExitTask( void *pvParameters )
{int car_id;while(1) {// 等待有车辆发出的离开通知(这里简化了触发机制)ulTaskNotifyTake( pdTRUE, portMAX_DELAY );// 释放信号量,增加一个空闲车位计数xSemaphoreGive( xParkingSpacesSemaphore );log("A car has left. Available spaces now: %d\n", uxSemaphoreGetCount(xParkingSpacesSemaphore) );}
}通过上面的例子,可以直观地看到信号量有以下几个核心特性和使用要点:
| 特性/操作 | 在例子中的体现 | 说明 |
| 资源计数 | 信号量的计数值 (5,4,3,...) 直接对应可用车位数。 | 计数信号量的值表示当前可用资源的数量 。 |
| 阻塞机制 | 车辆任务在 xSemaphoreTake时可能等待10秒。 | 如果资源不可用(计数值为0),任务可选择阻塞等待,让出CPU |
| 线程安全 | 多辆“车”任务同时申请车位,不会出现两个任务拿到同一个车位号的情况。 | 信号量的“获取”和“释放”操作是原子的,保证了资源分配的正确性。 |
| 优先级继承 | (此例未直接体现)高优先级的“救护车”任务若等待车位,可临时提升占用车位任务的优先级。 | 互斥信号量 (Mutex) 具备此特性,用于防止优先级反转,而计数信号量通常没有 |
