信号量
什么是信号量
信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问

信号量简介

- 当计数值大于0,表示有信号量资源。
- 当释放信号量,信号量计数值(资源数)加一。
- 当获取信号量,信号量计数值(资源数)减一。
- 信号量的计数值都是有限的:限定最大值。
- 如果最大值被限定为1,那么它就是二值信号量。
- 如果最大值不是1,它就是计数型信号量。
信号量:用于传递状态。
队列与信号量的对比
| 队列 | 信号量 |
|---|---|
| 可以容纳多个数据; 创建队列有两部分内存:队列结构体+队列项存储空间 | 仅存放计数值,无法存放其他数据; 创建信号量,只需分配信号量结构体 |
| 写入队列:当队列满时,可阻塞; | 释放信号量:不可阻塞,计数值++, 当计数值为最大值时,返回失败 |
| 读取队列:当队列为空时,可阻塞; | 获取信号量:计数值--, 当没有资源时,可阻塞 |
二值信号量
二值信号量的本质是一个队列长度为 1 的队列 ,该队列就只有空和满两种情况,这就是二值。
二值信号量通常用于互斥访问或任务同步, 与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题 ,所以二值信号量更适合用于同步!

二值信号量相关API函数
使用二值信号量的过程:创建二值信号量 > 释放二值信号量 > 获取二值信号量
| 函数 | 描述 |
|---|---|
| xSemaphoreCreateBinary() | 使用动态方式创建二值信号量 |
| xSemaphoreCreateBinaryStatic() | 使用静态方式创建二值信号量 |
| xSemaphoreGive() | 释放信号量 |
| xSemaphoreGiveFromISR() | 在中断中释放信号量 |
| xSemaphoreTake() | 获取信号量 |
| xSemaphoreTakeFromISR() | 在中断中获取信号量 |
创建二值信号量函数
SemaphoreHandle_t xSemaphoreCreateBinary( void )
#define xSemaphoreCreateBinary()
xQueueGenericCreate(1 , semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE)
#define semSEMAPHORE_QUEUE_ITEM_LENGTH (( uint8_t ) 0U)
#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) /* 队列 */
#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) /* 队列集 */
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) /* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) /* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) /* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) /* 递归互斥信号量 */
| 返回值 | 描述 |
|---|---|
| NULL | 创建失败 |
| 其他值 | 创建成功返回二值信号量的句柄 |
释放二值信号量函数
BaseType_t xSemaphoreGive( xSemaphore )
#define xSemaphoreGive ( xSemaphore )
xQueueGenericSend((QueueHandle_t)( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK)
#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
| 形参 | 描述 |
|---|---|
| xSemaphore | 要释放的信号量句柄 |
| 返回值 | 描述 |
|---|---|
| pdPASS | 释放信号量成功 |
| errQUEUE_FULL | 释放信号量失败 |
获取二值信号量函数
BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
| 形参 | 描述 |
|---|---|
| xSemaphore | 要获取的信号量句柄 |
| xBlockTime | 阻塞时间 |
| 返回值 | 描述 |
|---|---|
| pdTRUE | 获取信号量成功 |
| pdFALSE | 超时,获取信号量失败 |
实践

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/******************************************************************************************************/
QueueHandle_t semphore_handle;
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
semphore_handle = xSemaphoreCreateBinary();
if(semphore_handle != NULL)
{
printf("二值信号量创建成功!!!\r\n");
}
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handler );
xTaskCreate((TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,释放二值信号量 */
void task1( void * pvParameters )
{
uint8_t key = 0;
BaseType_t err;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
if(semphore_handle != NULL)
{
err = xSemaphoreGive(semphore_handle);
if(err == pdPASS)
{
printf("信号量释放成功!!\r\n");
}else printf("信号量释放失败!!\r\n");
}
}
vTaskDelay(10);
}
}
/* 任务二,获取二值信号量 */
void task2( void * pvParameters )
{
uint32_t i = 0;
BaseType_t err;
while(1)
{
err = xSemaphoreTake(semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */
if(err == pdTRUE)
{
printf("获取信号量成功\r\n");
}else printf("已超时%d\r\n",++i);
}
}
计数型信号量
计数型信号量相当于队列长度大于1 的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的
计数型信号量适用场合:
-
事件计数:当每次事件发生后,在事件处理函数中释放计数型信号量(计数值+1),其他任务
会获取计数型信号量(计数值-1) ,这种场合一般在创建时将初始计数值设置为 0
-
资源管理:信号量表示有效的资源数目。任务必须先获取信号量(信号量计数值-1 )才能获取资源控制权。
当计数值减为零时表示没有的资源。当任务使用完资源后,必须释放信号量(信号量计数值+1)
信号量创建时计数值应等于最大资源数目
计数型信号量相关API函数
使用计数型信号量的过程:创建计数型信号量 > 释放信号量 > 获取信号量
| 函数 | 描述 |
|---|---|
| xSemaphoreCreateCounting() | 使用动态方法创建计数型信号量。 |
| xSemaphoreCreateCountingStatic() | 使用静态方法创建计数型信号量 |
| uxSemaphoreGetCount() | 获取信号量的计数值 |
计数型信号量的释放和获取与二值信号量相同 !
计数型信号量创建函数
#define xSemaphoreCreateCounting( uxMaxCount , uxInitialCount )
xQueueCreateCountingSemaphore( ( uxMaxCount ) , ( uxInitialCount ) )
此函数用于创建一个计数型信号量 。
| 形参 | 描述 |
|---|---|
| uxMaxCount | 计数值的最大值限定 |
| uxInitialCount | 计数值的初始值 |
| 返回值 | 描述 |
|---|---|
| NULL | 创建失败 |
| 其他值 | 创建成功返回计数型信号量的句柄 |
获取计数型信号量计数值函数
#define uxSemaphoreGetCount( xSemaphore )
uxQueueMessagesWaiting(( QueueHandle_t )( xSemaphore ))
| 形参 | 描述 |
|---|---|
| xSemaphore | 信号量句柄 |
| 返回值 | 描述 |
|---|---|
| 整数 | 当前信号量的计数值大小 |
释放计数型信号量函数:BaseType_t xSemaphoreGive( xSemaphore )">释放计数型信号量函数:BaseType_t xSemaphoreGive( xSemaphore )
获取计数型信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )">获取计数型信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
实践

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/******************************************************************************************************/
QueueHandle_t count_semphore_handle;
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
count_semphore_handle = xSemaphoreCreateCounting(100 , 0); /* 创建计数型信号量 */
if(count_semphore_handle != NULL)
{
printf("计数型信号量创建成功!!!\r\n");
}
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handler );
xTaskCreate((TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,释放计数型信号量 */
void task1( void * pvParameters )
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
if(count_semphore_handle != NULL)
{
xSemaphoreGive(count_semphore_handle); /* 释放信号量 */
}
}
vTaskDelay(10);
}
}
/* 任务二,获取计数型信号量 */
void task2( void * pvParameters )
{
BaseType_t err = 0;
while(1)
{
err = xSemaphoreTake(count_semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */
if(err == pdTRUE)
{
printf("信号量的计数值为:%d\r\n",(int)uxSemaphoreGetCount(count_semphore_handle));
}
vTaskDelay(1000);
}
}
优先级翻转
优先级翻转
优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行
优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未知的严重后果。
在使用二值信号量的时候,经常会遇到优先级翻转的问题。
例如:

实践

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t low_task_handler;
void low_task( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t middle_task_handler;
void middle_task( void * pvParameters );
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t high_task_handler;
void high_task( void * pvParameters );
/******************************************************************************************************/
QueueHandle_t semphore_handle;
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
semphore_handle = xSemaphoreCreateBinary();
if(semphore_handle != NULL)
{
printf("二值信号量创建成功!!!\r\n");
}
xSemaphoreGive(semphore_handle); /* 释放一次信号量 */
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) low_task,
(char * ) "low_task",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &low_task_handler );
xTaskCreate((TaskFunction_t ) middle_task,
(char * ) "middle_task",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &middle_task_handler );
xTaskCreate((TaskFunction_t ) high_task,
(char * ) "high_task",
(configSTACK_DEPTH_TYPE ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(TaskHandle_t * ) &high_task_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,低优先级任务 */
void low_task( void * pvParameters )
{
while(1)
{
printf("low_task获取信号量\r\n");
xSemaphoreTake(semphore_handle,portMAX_DELAY);
printf("low_task正在运行!!!\r\n");
delay_ms(3000);
printf("low_task释放信号量\r\n");
xSemaphoreGive(semphore_handle);
vTaskDelay(1000);
}
}
/* 任务二,中优先级任务 */
void middle_task( void * pvParameters )
{
while(1)
{
printf("middle_task正在运行!!!\r\n");
vTaskDelay(1000);
}
}
/* 任务三,高优先级任务 */
void high_task( void * pvParameters )
{
while(1)
{
printf("high_task获取信号量\r\n");
xSemaphoreTake(semphore_handle,portMAX_DELAY);
printf("high_task正在运行!!!\r\n");
delay_ms(1000);
printf("high_task释放信号量\r\n");
xSemaphoreGive(semphore_handle);
vTaskDelay(1000);
}
}
实验结果
如果低优先级任务获取到信号量 此时高优先级任务进入运行态尝试获取信号量 失败而阻塞 不能执行 然而中优先级任务 不需要信号量则可以正常执行,待中优先级任务执行完后,低优先级任务得以执行最后低优先级任务释放信号量 此时高优先级任务才能执行。
这就是优先级翻转,高优先级的任务无法优先执行 反而中优先级最早 低优先级次之 高优先级最后。
可以给高优先级任务执行前加一个阻塞,更容易得到相应结论。
互斥信号量
互斥信号量
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!
什么是优先级继承
优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
互斥信号量可以解决上述实验的问题, 此时低优先级任务的优先级被提升到与高优先级任务相同此时中优先级任务就无法提前执行将优先级翻转的危害降到了最低
优先级继承示例

互斥信号量的注意事项
优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响
注意:互斥信号量不能用于中断服务函数中,原因如下:
(1) 互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以互斥信号量只能用与任务中,不能用于中断服务函数。
(2) 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
互斥信号量相关API函数
使用互斥信号量:首先将宏configUSE_MUTEXES置1.
使用流程:创建互斥信号量 > (task)获取信号量 >(give)释放信号量
创建互斥信号量函数:
| 函数 | 描述 |
|---|---|
| xSemaphoreCreateMutex() | 使用动态方法创建互斥信号量。 |
| xSemaphoreCreateMutexStatic() | 使用静态方法创建互斥信号量。 |
互斥信号量的释放和获取函数与二值信号量相同 !只不过互斥信号量不支持中断中调用
注意:创建互斥信号量时,会主动释放一次信号量
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
此函数用于创建互斥信号量
| 返回值 | 描述 |
|---|---|
| NULL | 创建失败 |
| 其他值 | 创建成功返回互斥信号量的句柄 |
释放和获取互斥信号量函数">释放和获取互斥信号量函数
释放信号量函数:BaseType_t xSemaphoreGive( xSemaphore )">释放信号量函数:BaseType_t xSemaphoreGive( xSemaphore )
获取信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )">获取信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
实践

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t low_task_handler;
void low_task( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t middle_task_handler;
void middle_task( void * pvParameters );
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t high_task_handler;
void high_task( void * pvParameters );
/******************************************************************************************************/
QueueHandle_t mutex_semphore_handle;
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
mutex_semphore_handle = xSemaphoreCreateMutex(); /* 创建互斥信号量,并且主动释放一次信号量 */
if(mutex_semphore_handle != NULL)
{
printf("互斥信号量创建成功!!!\r\n");
}
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) low_task,
(char * ) "low_task",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &low_task_handler );
xTaskCreate((TaskFunction_t ) middle_task,
(char * ) "middle_task",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &middle_task_handler );
xTaskCreate((TaskFunction_t ) high_task,
(char * ) "high_task",
(configSTACK_DEPTH_TYPE ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(TaskHandle_t * ) &high_task_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,低优先级任务 */
void low_task( void * pvParameters )
{
while(1)
{
printf("low_task获取信号量\r\n");
xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);
printf("low_task正在运行!!!\r\n");
delay_ms(3000);
printf("low_task释放信号量\r\n");
xSemaphoreGive(mutex_semphore_handle);
vTaskDelay(1000);
}
}
/* 任务二,中优先级任务 */
void middle_task( void * pvParameters )
{
while(1)
{
printf("middle_task正在运行!!!\r\n");
vTaskDelay(1000);
}
}
/* 任务三,高优先级任务 */
void high_task( void * pvParameters )
{
while(1)
{
printf("high_task获取信号量\r\n");
xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);
printf("high_task正在运行!!!\r\n");
delay_ms(1000);
printf("high_task释放信号量\r\n");
xSemaphoreGive(mutex_semphore_handle);
vTaskDelay(1000);
}
}
总结