FreeRTOS 学习五:信号量和互斥锁

时间:2021-07-18 15:11:40

1. 简介:

  1. 此篇文章中涉及的函数除特殊说明,包含的头文件都是 semphr.h
  2. 二值信号量同linux中的原子量,我们可以看成像是一个锁,在使用的时候,需要能拿到锁才能执行程序,尝试拿不到锁,不能运行。
  3. 二值信号量和互斥锁功能很相似,但是也有一些微妙的不同,互斥锁包括一个优先级集成机制,二值信号量没有。因此,任务和任务、任务和中断之间的同步的时候,二值信号量是一个更好的选择。简单的排斥情况使用互斥锁

2. 函数

2.1 二值信号量创建:

typedef void * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;

SemaphoreHandle_t xSemaphoreCreateBinary( void );
返回值:
非NULL,返回的是一个二值信号量的指针又叫句柄
NULL,因内存不足,创建不成功
说明:
1.在FreeRTOS的这个函数的界面上有一个重要的提示,在大多数情况下,直接使用任务的notification会比直接使用这个二值信号量要对内存使用高效,此函数依然
2.这个函数的使用需要配置宏 configSUPPORT_DYNAMIC_ALLOCATION = 1,不过这个值默认就是1
3.每个二值信号量都需要一点ram空间来保存信号量的状态
4.此函数也有一个xSemaphoreCreateBinaryStatic()函数,用于在编译的时候就确定在ram中的位置
5.vSemaphoreCreateBinary函数是之前版本的函数,现版本使用的是xSemaphore…

2.2 信号量创建:

SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
参数:
uxMaxCount,最大计数量
uxInitialCount ,信号量的初始值,当此信号量用于资源管理,值应该为0,当用于资源管理时,应该设为uxMaxCount
返回值:
非NULL,信号量的句柄
NULL,因内存空间不足,创建失败
说明:
1.这个函数的使用需要配置宏 configSUPPORT_DYNAMIC_ALLOCATION = 1,不过这个值默认就是1
2.此函数也有一个static后缀的函数:xSemaphoreCreateCountingStatic,在是编译的时候分配固定的地址

2.3 互斥量创建:

SemaphoreHandle_t xSemaphoreCreateMutex( void );
返回值:
非NULL,信号量的句柄
NULL,因内存空间不足,创建失败
说明:
1.这个函数的使用需要配置宏 configSUPPORT_DYNAMIC_ALLOCATION = 1,不过这个值默认就是1
2.此函数也有一个static后缀的函数:xSemaphoreCreateMutexStatic,在是编译的时候分配固定的地址

2.4 递归互斥锁创建:

递归互斥锁的使用是为了部分情况下解决死锁的问题,死锁出现的情况如下代码:
// 不加锁版本
void foo_nolock()
{
// do something
}
// 加锁版本
void fun()
{
mutex.lock();
foo_nolock();
mutex.unlock();
}

言归正传:

SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );
返回值:
非NULL,信号量的句柄
NULL,因内存空间不足,创建失败
说明:
1.此函数需要配置 configSUPPORT_DYNAMIC_ALLOCATION = 1 和 configUSE_RECURSIVE_MUTEXES = 1,默认值,两个都是1
2.有一个static后缀的函数,此处不多说,需要配置configSUPPORT_DYNAMIC_ALLOCATION = 0

2.5 删除信号量:

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
参数:
xSemaphore,要操作的信号量的句柄
说明:
能删除递归信号量和非递归的信号量
不要删除阻塞任务的信号量

2.6 获取信号量:

xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
/* 中断中使用 */
xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken );
/* 递归互斥量时获取 */
xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex, TickType_t xTicksToWait );
参数:
xSemaphore,信号量的句柄
xMutex,互斥锁的句柄
xTicksToWait,阻塞等待时间,portTICK_PERIOD_MS用于将ms单位转换成tick,如果 INCLUDE_vTaskSuspend = 1,这个值设成portMAX_DELAY,则会限阻塞等待
pxHigherPriorityTaskWoken,如果中断中调用中断的这个函数引起一个任务从阻塞态变成非阻塞状态,并且变成非阻塞状态的优先级高于目前的任务,这个指针指向的变量的值变成pdTRUE
xSemaphoreTake和xSemaphoreTakeRecursive返回值:
pdTRUE,获取成功
pdFALSE,时间超时后,还没得到信号量
xSemaphoreTakeFromISR返回值:
pdTRUE,获取成功
pdFALSE,获取不成功

2.7 归还/释放信号量:

xSemaphoreGive( SemaphoreHandle_t xSemaphore );
/* 中断中使用 */
xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken );
/* 递归互斥量时使用 */
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex);
参数:
xSemaphore,信号量的句柄
xMutex,互斥锁的句柄
xTicksToWait,阻塞等待时间,portTICK_PERIOD_MS用于将ms单位转换成tick,如果 INCLUDE_vTaskSuspend = 1,这个值设成portMAX_DELAY,则会限阻塞等待
pxHigherPriorityTaskWoken,如果中断中调用中断的这个函数引起一个任务从阻塞态变成非阻塞状态,并且变成非阻塞状态的优先级高于目前的任务,这个指针指向的变量的值变成pdTRUE,之后应该有一个任务上线文的切换
xSemaphoreGive返回值:
pdTRUE,释放成功
pdFALSE,释放出现错误
xSemaphoreGiveFromISR返回值:
pdTRUE,释放成功
errQUEUE_FULL,释放出现错误
xSemaphoreGiveRecursive返回值:
pdTRUE,释放成功

2.8 其他对信号量的操作:

/* 查询信号量的数目 */
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
/* 查询拥有互斥锁的任务句柄 */
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
uxSemaphoreGetCount返回值:
返回信号量的数目
xSemaphoreGetMutexHolder返回值:
非NULL,任务持有互斥信号量的任务句柄
NULL,xMutex不是一个互斥信号量或者信号量没有被任务持有
xSemaphoreGetMutexHolder需要注意:
需要配置configUSE_MUTEXES = INCLUDE_xSemaphoreGetMutexHolder = 1