网站开发工程师职责,多用户商城网站建设公司,公司注册要求,wordpress 搬家 文章 404这里写目录标题 一、信号量的简介#xff08;了解#xff09;二、二值信号量#xff08;熟悉#xff09;三、二值信号量实验#xff08;掌握#xff09;四、计数型信号量#xff08;熟悉#xff09;五、计数型信号量实验#xff08;掌握#xff09;六、优先级翻转简介… 这里写目录标题 一、信号量的简介了解二、二值信号量熟悉三、二值信号量实验掌握四、计数型信号量熟悉五、计数型信号量实验掌握六、优先级翻转简介熟悉七、优先级翻转实验掌握八、互斥信号量熟悉九、互斥信号量实验掌握 一、信号量的简介了解
信号量是一种解决同步问题的机制可以实现对共享资源的有序访问
假设有一个人需要在停车场停车 1、首先判断停车场是否还有空车位判断信号量是否有资源 2、停车场正好有空车位信号量有资源那么就可以直接将车开入空车位进行停车获取信号量成功 3、停车场已经没有空车位了信号量没有资源那么这个人可以选择不停车获取信号量失败 也可以选择等待任务阻塞其他人将车开出停车场释放信号量资源 然后再将车停入空车位 。 当计数值大于0代表有信号量资源 当释放信号量信号量计数值资源数加一 当获取信号量信号量计数值资源数减一
信号量的计数值都有限制限定最大值。 如果最大值被限定为1那么它就是二值信号量 如果最大值不是1它就是计数型信号量。
信号量用于传递状态
队列与信号量的对比
二、二值信号量熟悉
二值信号量的本质是一个队列长度为 1 的队列 该队列就只有空和满两种情况这就是二值。 二值信号量通常用于互斥访问或任务同步 与互斥信号量比较类似但是二值信号量有可能会导致优先级翻转的问题 所以二值信号量更适合用于同步 二值信号量相关API函数熟悉 使用二值信号量的过程创建二值信号量 、 释放二值信号量 、 获取二值信号量 创建二值信号量函数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 ) /* 递归互斥信号量 */ 释放二值信号量函数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 )获取二值信号量函数BaseType_t xSemaphoreTake( xSemaphore, xBlockTime ) 三、二值信号量实验掌握
1、实验目的学习 FreeRTOS 的二值信号量相关API函数的使用 2、实验设计将设计三个任务start_task、task1、task2 三个任务的功能如下
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 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函数
#define xSemaphoreCreateCounting( uxMaxCount , uxInitialCount ) \ xQueueCreateCountingSemaphore( ( uxMaxCount ) , ( uxInitialCount ) ) 此函数用于创建一个计数型信号量 。
#define uxSemaphoreGetCount( xSemaphore ) \ uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )此函数用于获取信号量当前计数值大小
五、计数型信号量实验掌握
1、实验目的学习 FreeRTOS 的计数型信号量相关API函数的使用 2、实验设计将设计三个任务start_task、task1、task2 三个任务的功能如下
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 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);}
}
六、优先级翻转简介熟悉
优先级翻转高优先级的任务反而慢执行低优先级的任务反而优先执行 优先级翻转在抢占式内核中是非常常见的但是在实时操作系统中是不允许出现优先级翻转的因为优先级翻转会破坏任务的预期顺序可能会导致未知的严重后果。 在使用二值信号量的时候经常会遇到优先级翻转的问题。
举个例子 高优先级任务被低优先级任务阻塞导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看就像是中优先级的任务比高优先级任务具有更高的优先权即优先级翻转
七、优先级翻转实验掌握
1、实验目的在使用二值信号量的时候会存在优先级翻转的问题本实验通过模拟的方式实现优先级翻转观察优先级翻转对抢占式内核的影响 2、实验设计将设计四个任务start_task、high_task、 middle_task low_task 四个任务的功能如下
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 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);}
}
八、互斥信号量熟悉
互斥信号量其实就是一个拥有优先级继承的二值信号量在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中 优先级继承当一个互斥信号量正在被一个低优先级的任务持有时 如果此时有个高优先级的任务也尝试获取这个互斥信号量那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
优先级继承示例 此时任务H的阻塞时间仅仅是任务L 的执行时间将优先级翻转的危害降到了最低
优先级继承并不能完全的消除优先级翻转的问题它只是尽可能的降低优先级翻转带来的影响 注意互斥信号量不能用于中断服务函数中原因如下 (1) 互斥信号量有任务优先级继承的机制 但是中断不是任务没有任务优先级 所以互斥信号量只能用与任务中不能用于中断服务函数。 (2) 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
互斥信号量相关API函数熟悉 使用互斥信号量首先将宏configUSE_MUTEXES置1 使用流程创建互斥信号量 、task获取信号量 、give释放信号量 互斥信号量的释放和获取函数与二值信号量相同 只不过互斥信号量不支持中断中调用 注意创建互斥信号量时会主动释放一次信号量
互斥信号量创建API函数
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )此函数用于创建互斥信号量
九、互斥信号量实验掌握
1、实验目的在优先级翻转实验的基础加入互斥信号量解决优先级翻转问题 2、实验设计将优先级翻转所用到的信号量函数修改成互斥信号量即可通过串口打印提示信息
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 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);}
}