STM32与FreeRTOS结合应用中的信号量详解
信号量:
它为一个经典的同步工具,用来处理线程同步问题,尤其是共享资源的访问控制。
FreeRTOS的两个主要信号量类型:二值信号量和计数信号量。其中二值信号量包含一特殊“互斥型信号量”
一、二值信号量
定义:
仅能储存2种状态值,用于在任务之间同步或实现简单的二进制状态的互斥访问。
作用:
1、同步:
可以像普通的信号量一样用于任务间的同步
2、简单的互斥访问:
它也可以用于简单的互斥访问共享资源(类似于互斥锁)。当一个任务获取了二值信号量,其他任务在获取该信号量时会被阻塞,直到它被释放。
特点:
1、二值信号量是数值型信号量的特殊形式:
计数范围为0或1。
2、它没有内置的优先级继承机制:
当低优先级任务正持有某二值信号量时,高优先级任务由于无法获取信号量的值而被阻塞,就是说高优先级任务无法先一步低优先级任务执行,在执行效果上优先级被反转。显然违背了实时操作系统的实时性。
使用:
1、 创建:(动态)
使用 xSemaphoreCreateBinary() 或 xSemaphoreCreateBinaryStatic() 函数创建二值信号量。
定义信号量类型变量接受信号量句柄:
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary(void);//该函数无参数,初始信号量为0(不可用)。
创建成功返回信号量句柄,创建失败返回NULL。
显式激活:
二值信号量初始值为0,需要手动激活:
xSemaphoreGive(xBinarySemaphore); // 将信号量设置为 1
2、创建:(静态)
分配静态缓冲区:
StaticSemaphore_t xStaticSemaphoreBuffer;
创建静态二值信号量,将静态缓冲区作为参数传递:
定义信号量类型变量接受信号量句柄:
SemaphoreHandle_t xSemaphore =
xSemaphoreCreateBinaryStatic( &xStaticSemaphoreBuffe );
显式激活:
二值信号量初始值为0,需要手动激活:
xSemaphoreGive(xBinarySemaphore); // 将信号量设置为 1
二值信号量无优先级继承机制!!!!!
二值信号量无优先级继承机制!!!!!
二、计数型信号量(多值信号量)
多值信号量的核心功能应该是允许多个任务共享资源,同时还能控制资源的并发访问数量。它更侧重于资源的管理和分配。任务间通信可以用信号量来同步事件,比如一个任务生成事件,另一个任务等待事件;资源管理则是用信号量来控制对共享资源的访问,比如多个任务访问多个打印机。这些例子很好懂,我可以直接用。
使用:(动态)
创建多值信号量:
SemaphoreHandle_t xCountingSemaphore = xSemaphoreCreateCounting(10, 0);
其中xSemaphoreCreateCounting的原型为:
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount
, UBaseType_t uxInitialCount);
形参解释:
uxMaxCount:信号量的最大计数值 uxInitialCount:信号量的初始计数值
函数返回值及其特性:
返回值:
成功的话返回一个指向信号量的指针(句柄),该句柄用于后续对信号量的操作。
失败的话:如果由于内存不足等原因无法创建信号量,函数返回 NULL
特性:
优先级继承:
当一个高优先级任务等待一个由低优先级任务持有的资源时,FreeRTOS 会通过临时提升低优先级任务的优先级来避免优先级翻转问题。
优先级继承机制由系统自动完成 无需用户显性操作。
获取信号量:
使用BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
参数解释:
xSemaphore: 信号量句柄,该值必须使用创建信号量的函数获取
xTicksToWait:任务等待信号量的最长时间(单位为 ticks)。如果设置为portMAX_DELAY,任务将无限等待,直到信号量变为可用状态。
返回值:
pdPASS:成功获取信号量。
pdFAIL:未获取到信号量,可能是信号量不可用且等待时间已到,或参数不合法。
三、互斥型信号量(互斥锁)
互斥锁是一种特殊的二进制信号量,用于保护临界资源,确保同一时刻只有一个线程能够访问共享资源。它只有2种状态:开锁(未被占用)与关锁(被占用)。
互斥锁的闭锁状态(即被占用状态)只能被一个线程持有:
一旦某个线程获取互斥锁后,互斥锁变为闭锁状态,其他线程无法获取该锁。
工作原理:
- 加锁:当线程需要访问共享资源时,会尝试获取互斥锁。如果互斥锁处于开锁状态,则线程获取锁成功,互斥锁变为闭锁状态,线程可以访问资源
- 阻塞等待:如果互斥锁已被其他线程占用(闭锁状态),则当前线程会被阻塞,进入等待队列,直到互斥锁被释放
- 解锁:当持有互斥锁的线程完成对共享资源的访问后,会释放互斥锁,互斥锁变为开锁状态。此时,等待队列中的线程会被唤醒,尝试获取互斥锁。
特性:
- 互斥性:确保同一时刻只有一个线程能够访问共享资源,避免了多线程同时访问导致的数据不一致
- 优先级继承:为了避免优先级反转问题,互斥锁通常支持优先级继承机制。当一个低优先级线程持有互斥锁时,如果有高优先级线程请求该锁,低优先级线程的优先级会被临时提升,直到它释放锁。
- 递归访问:某些互斥锁支持递归访问,即同一个线程可以多次获取同一个互斥锁而不会导致死锁。
- 中断中的不可用:互斥锁不能在中断服务例程中使用,因为中断无法保持阻塞等待
使用:
创建互斥锁:
SemaphoreHandle_t xSemaphoreCreateMutex(void);
创建成功返回互斥锁句柄,创建失败返回NULL
获取互斥锁:
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait);
成功获取互斥锁返回pdTRUE;失败返回pdFALSE
参数解释:
xSemaphore:互斥锁句柄
xTicksToWait:获取互斥锁等待时间,该参数为:portMAX_DELAY时则会无限等待。
释放互斥锁:
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
如果成功释放,返回返回pdTRUE;失败返回pdFALSE
参数解释:
xSemaphore:互斥锁的句柄
作者:推推发际线