前言
通过学习上一章互斥量理论基础,这一章我们来做一些实验进行验证。
一、互斥量与二进制信号量
互斥量使用和二进制信号量类似
- 互斥量有优先级继承功能,二进制信号量没有
- Give/Take函数完全一样
- 二进制信号量的初始值是0,互斥量的初始值是1
二、优先级反转与优先级继承
首先创建三个优先级不同的任务
xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );
xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );
xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );
创建互斥量/二进制信号量
SemaphoreHandle_t xLock;
// xLock = xSemaphoreCreateBinary( );
xLock = xSemaphoreCreateMutex( );
xSemaphoreGive(xLock);
三个优先级不同的任务处理不同事情,验证二进制信号量的优先级反转和互斥量的优先级继承功能
/*-----------------------------------------------------------*/
static void vLPTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );
uint32_t i;
char c = 'A';
printf("LPTask start\r\n");
/* 无限循环 */
for( ;; )
{
flagLPTaskRun = 1;
flagMPTaskRun = 0;
flagHPTaskRun = 0;
/* 获得互斥量/二进制信号量 */
xSemaphoreTake(xLock, portMAX_DELAY);
/* 耗时很久 */
printf("LPTask take the Lock for long time");
for (i = 0; i < 26; i++)
{
flagLPTaskRun = 1;
flagMPTaskRun = 0;
flagHPTaskRun = 0;
printf("%c", c + i);
}
printf("\r\n");
/* 释放互斥量/二进制信号量 */
xSemaphoreGive(xLock);
vTaskDelay(xTicksToWait);
}
}
static void vMPTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 30UL );
flagLPTaskRun = 0;
flagMPTaskRun = 1;
flagHPTaskRun = 0;
printf("MPTask start\r\n");
/* 让LPTask、HPTask先运行 */
vTaskDelay(xTicksToWait);
/* 无限循环 */
for( ;; )
{
flagLPTaskRun = 0;
flagMPTaskRun = 1;
flagHPTaskRun = 0;
}
}
static void vHPTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );
flagLPTaskRun = 0;
flagMPTaskRun = 0;
flagHPTaskRun = 1;
printf("HPTask start\r\n");
/* 让LPTask先运行 */
vTaskDelay(xTicksToWait);
/* 无限循环 */
for( ;; )
{
flagLPTaskRun = 0;
flagMPTaskRun = 0;
flagHPTaskRun = 1;
printf("HPTask wait for Lock\r\n");
/* 获得互斥量/二进制信号量 */
xSemaphoreTake(xLock, portMAX_DELAY);
flagLPTaskRun = 0;
flagMPTaskRun = 0;
flagHPTaskRun = 1;
/* 释放互斥量/二进制信号量 */
xSemaphoreGive(xLock);
}
}
/*-----------------------------------------------------------*/
二进制信号量 实现优先级反转,中优先级先于高优先级执行
互斥量实现优先级继承
三、递归锁
创建递归锁
/* 递归锁句柄 */
SemaphoreHandle_t xMutex;
xMutex = xSemaphoreCreateRecursiveMutex( );
创建2个任务: 一个上锁, 另一个自己监守自盗(开别人的锁自己用)
xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL );
xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL );
/* 启动调度器 */
vTaskStartScheduler();
任务描述
/*-----------------------------------------------------------*/
static void vTakeTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
BaseType_t xStatus;
int i;
/* 无限循环 */
for( ;; )
{
/* 获得递归锁: 上锁 */
xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
printf("Task1 take the Mutex in main loop %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
/* 阻塞很长时间, 让另一个任务执行,
* 看看它有无办法再次获得递归锁
*/
vTaskDelay(xTicksToWait);
for (i = 0; i < 10; i++)
{
/* 获得递归锁: 上锁 */
xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
printf("Task1 take the Mutex in sub loop %s, for time %d\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed", i);
/* 释放递归锁 */
xSemaphoreGiveRecursive(xMutex);
}
/* 释放递归锁 */
xSemaphoreGiveRecursive(xMutex);
}
}
static void vGiveAndTakeTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );
BaseType_t xStatus;
/* 尝试获得递归锁: 上锁 */
xStatus = xSemaphoreTakeRecursive(xMutex, 0);
printf("Task2: at first, take the Mutex %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
/* 如果失败则监守自盗: 开锁 */
if (xStatus != pdTRUE)
{
/* 无法释放别人持有的锁 */
xStatus = xSemaphoreGiveRecursive(xMutex);
printf("Task2: give Mutex %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
}
/* 如果无法获得, 一直等待 */
xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
printf("Task2: and then, take the Mutex %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
/* 无限循环 */
for( ;; )
{
/* 什么都不做 */
vTaskDelay(xTicksToWait);
}
}
/*-----------------------------------------------------------*/
结果