关于互斥信号量和二值信号量的区别
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于互斥信号量和二值信号量的区别相关的知识,希望对你有一定的参考价值。
参考技术A 用于任务同步和中断同步,也可以实现互斥访问,但不具有优先级继承通过二值信号量实现互斥访问:
1.创建3个任务task1,task2,task3,优先级分别是3,2,1.
2. 开始task3首先获得二值信号量资源,但task1优先级比task3高抢占了task3的cpu使用权
3. task1也需要获取二值信号量,所以task1就会挂起,等待task3释放二值信号量。
4. 由于 task2已经处于就绪态,并且优先级比task3高,task2抢占了task3的cpu使用权,此时优先级翻转就发生了,task1(高优先任务)需要等待task2(低优先任务)运行完后才能运行,task3任务继续执行并释二值信号量资源,task1才能获取到二值信号量,从而可以继续执行
互斥信号量简单说是具有优先级继承的二值信号量,用于进程中的互斥,不可用于中断中(1:具有优先级继承机制,2:中断服务函数不能因为等待互斥信号量而阻塞)
互斥信号量优先级继承机制:当一个低优先级的任务正在使用这个互斥信号量时,高优先的任务在等待这个互斥信号量的时候,高优先级的任务会将低优先级的任务的优先级提到和自己同一个水平,从而来避免位于低优先和高优先的任务抢占cpu时间运行,而导致次优先级任务先于高优先级的任务运行,引起优先级翻转。
优先级继承也只是尽可能的降低优先级翻转的发生,软件设计的时候需避免优先级翻转的问题发生
通过互斥信号量实现互斥访问:
1.一开始task3开始运行,先获取到互斥锁
2. task1开始运行尝试去获取互斥锁失败被阻塞等待task3执行完,但是此时提升task3的优先级,让其优先级跟自己一样
3.task3运行过程中,task2被触发,由于其优先级低于task3(第2步被提升过),task2等待运行
4.继续运行task3,运行完后释放互斥锁5.task1继续运行6.task1执行完,执行task2所以过程跟前面的虽然一样,但是互斥锁多做了一个步骤就是将task3的优先级提升到task1的级别,防止task2中途出来搅局浪费大量时间
FreeRTOS学习笔记 ——二值信号量
前言
上一个笔记学习完了FreeRTOS的消息队列,以及如何创建与使用,在本篇文章中,继续基于上一个工程来学习FreeRTOS的信号量,其中二值信号量是尤其重要的一点,比较常用,所以本篇会着重介绍二值信号量作用与使用。
FreeRTOS信号量简介
- 二值信号量通常用于互斥访问或同步,二值信号量和互斥信号量非常类似,但是还是有一 些细微的差别,互斥信号量拥有优先级继承机制,二值信号量没有优先级继承。因此二值信号 另更适合用于同步(任务与任务或任务与中断的同步),而互斥信号量适合用于简单的互斥访问。
- 二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空 的,这不正好就是二值的吗? 任务和中断使用这个特殊队列不用在乎队列中存的是什么消息,只需要知道这个队列是满的还是空的。可以利用这个机制来完成任务与中断之间的同步或是任务与任务之间的同步。
下面进入工程创建。
CubeMx配置
MCU: STM32F103C8T6
CubeMX: STM32CubeMX 5.3.0
在上篇文章的CubeMx配置基础上,增加内容,如果有基本工程不会创建的小伙伴可以点击传送门进行学习。
在Timers and Semaphores栏里在Binary Semaphores点击add,新增一个二值信号量。
接下来就像往常那样创建并打开工程就可以了
填写项目名
配置项目生成单独的.c/.h文件
接着生成代码就ok了~ (点击后会出现警告,直接点yes即可)
打开工程,freertos.c中会发现多出这段代码
osSemaphoreDef(myBinarySem01);
myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);
也就是创建二值信号量的代码。
下面的测试demo与上篇文章差不多,在原有基础上,增加二值信号量,使得两个任务可以同步起来,第一个任务把信息放入队列里后并产生一个随机的延时数(用于测试),然后将二值信号量释放出去;任务二无限时长等待信号量,如果获取信号量成功,则将队列里的信息出队,并打印出来。
下面为演示代码。
=加入头文件以及变量=
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdlib.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef struct
uint8_t mid;
char mDate[20];
MSG;
MSG myDate;
uint16_t cnt=1;
uint16_t d_time=0;
/* USER CODE END PTD */
再编写task里的代码
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
/* USER CODE BEGIN StartDefaultTask */
MSG *TXMSG;
uint8_t i;
TXMSG = &myDate;
/* Infinite loop */
for(;;)
TXMSG->mid = cnt++;
for(i=0; i<20; i++)
TXMSG->mDate[i] = rand()%255;
if(xQueueSend(myQueue02Handle,&TXMSG,10) ==errQUEUE_FULL)
printf("myQueue01Handle errQUEUE_FULL\\r\\n");
d_time = rand()%500;
osDelay(d_time);
xSemaphoreGive(myBinarySem01Handle);//释放信号量
printf("\\r\\nTX-Task1 Done!\\r\\n");
/* USER CODE END StartDefaultTask */
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
/* USER CODE BEGIN StartTask02 */
MSG *RXMSG;
uint8_t i;
/* Infinite loop */
for(;;)
xSemaphoreTake(myBinarySem01Handle,osWaitForever);//获取信号量
if(xQueueReceive( myQueue02Handle,&RXMSG, 10) == pdPASS)
printf("\\r\\nRXMSG->ucMessageID = %d \\r",RXMSG->mid);
printf("RXMSG->ucData[0] = ");
for(i=0;i<20;i++)
printf(" %03d",RXMSG->mDate[i]);
printf("\\r\\n");
printf("delay time: %d RX-Task2 Done!\\r\\n",d_time);
/* USER CODE END StartTask02 */
打开串口工具进行测试
可以发现首先Task1先进行信息推进队列里,并随机产生几百毫秒的延时,随后Task2才开始工作,说明二值信号量使得它们同步了。
关于信号量的内容还有计数信号量、互斥信号量和递归互斥信号量,这里就不做解释与实验了。
以上内容记录下来,希望能帮助到有需要的伙伴。
该文章如有不对地地方,欢迎指出。
以上是关于关于互斥信号量和二值信号量的区别的主要内容,如果未能解决你的问题,请参考以下文章