FreeRTOS信号量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZenNaiHeQiao/article/details/83749885

FreeRTOS中信号量又分为二值信号量计数型信号量互斥信号量递归互斥信号量

1:二值信号量

二值信号量通常用于互斥访问或同步,二值信号量和互斥信号量非常类似,但是还是有一
些细微的差别,互斥信号量拥有优先级继承机制,二值信号量没有优先级继承。因此二值信号
另更适合用于同步(任务与任务或任务与中断的同步),而互斥信号量适合用于简单的互斥访问.

在这里插入图片描述
创建:

函数名 原型 功能
vSemaphoreCreateBinary () void vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore ) 动 态 创 建 二 值 信 号 量(旧)
xSemaphoreCreateBinary() SemaphoreHandle_t xSemaphoreCreateBinary( void ) 动 态 创 建 二 值 信 号 量
xSemaphoreCreateBinaryStatic() SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer ) 静态创建二值信号量

*新版函数创建的二值信号量默认是无效的,而老版本是有效的

释放:

函数名 原型 功能
xSemaphoreGive() BaseType_t xSemaphoreGive( xSemaphore ) 任务级信号量释放函数
xSemaphoreGiveFromISR() BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,BaseType_t * pxHigherPriorityTaskWoken) 中断级信号量释放函数

获取:
“带走(Taking)”一个信号量意为”获取(Obtain)”或”接收(Receive)”信号量。只有当信号量有效的时候才可以被获取。

函数名 原型 功能
xSemaphoreTake() BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xBlockTime) 任务级获取信号量函数
xSemaphoreTakeFromISR() BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t * pxHigherPriorityTaskWoken) 中断级获取信号量函数

应用:

taskENTER_CRITICAL(); 
SemaphoreHandle_t BinarySemaphore; //二值信号量句柄
BinarySemaphore=xSemaphoreCreateBinary();
taskEXIT_CRITICAL(); //退出临界区
...........................

void  task  (void )
{
BaseType_t err=pdFALSE;
while(1)
{
if(BinarySemaphore  !=NULL)   //检查信号量是否成功创建,进入处理
  {
err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY);//获取信号量
if(err==pdTRUE)//获取成功
    {
       ............
    } 
  }
}
}
...........................
void XXX_IRQ(void)
{
//释放二值信号量
if(BinarySemaphore!=NULL)
{
xSemaphoreGiveFromISR(BinarySemaphore,&xHigherPriorityTaskWoken);  
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
}
}

2:计数型信号量

计数型信号量叫做数值信号量,二值信号量相当于长度为 1 的队列,那么计数型信号量就是长度大于 1 的队列。同二值信号量一样,用户不需要关心队列中存储了什么数据,只需要关心队列是否为空即可。计数型信号量通常用于如下两个场合:
1 、事件计数
在这个场合中,每次事件发生的时候就在事件处理函数中释放信号量(增加信号量的计数值),其他任务会获取信号量(信号量计数值减一,信号量值就是队列结构体成员变量uxMessagesWaiting)来处理事件。在这种场合中创建的计数型信号量初始计数值为 0。
2 、资源管理
在这个场合中,信号量值代表当前资源的可用数量,比如停车场当前剩余的停车位数量。一个任务要想获得资源的使用权,首先必须获取信号量,信号量获取成功以后信号量值就会减一。当信号量值为 0 的时候说明没有资源了。当一个任务使用完资源以后一定要释放信号量,释放信号量以后信号量值会加一。在这个场合中创建的计数型信号量初始值应该是资源的数量,比如停车场一共有 100 个停车位,那么创建信号量的时候信号量值就应该初始化为 100。

创建:

函数名 原型 功能
xSemaphoreCreateCounting() SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,UBaseType_t uxInitialCount ) 使用动态方法创建计数型信号量。
xSemaphoreCreateCountingStatic() SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,UBaseType_t uxInitialCount,StaticSemaphore_t * pxSemaphoreBuffer ) 使用静态方法创建计数型信号量

释放和获取: 计数型信号量的释放和获取与二值信号量相同
应用:

//计数型信号量句柄
SemaphoreHandle_t CountSemaphore;//计数型信号量
taskENTER_CRITICAL(); //进入临界区
CountSemaphore=xSemaphoreCreateCounting(255,0); 
taskEXIT_CRITICAL(); //退出临界区
.............................................
u8 semavalue;
BaseType_t err;
if(CountSemaphore!=NULL) //检查信号量是否成功创建,计数型信号量创建成功
{
		err=xSemaphoreGive(CountSemaphore);//释放计数型信号量 
		if(err==pdFALSE){printf("信号量释放失败!!!\r\n");}
		semavalue=uxSemaphoreGetCount(CountSemaphore);  //获取计数型信号量值
}
.............................................
{
u8 semavalue;
xSemaphoreTake(CountSemaphore,portMAX_DELAY); //等待数值信号量 
semavalue=uxSemaphoreGetCount(CountSemaphore); //获取数值信号量值 
}

3:互斥信号量

在使用二值信号量时候会遇到优先级翻转这一情况,引申出来互斥信号量这一概念。
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。
互斥信号量不能用于中断服务函数中.
创建:

函数名 原型 功能
xSemaphoreCreateMutex() SemaphoreHandle_t xSemaphoreCreateMutex( void ) 使用动态方法创建互斥信号量。
xSemaphoreCreateMutexStatic() SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer ) 使用静态方法创建互斥信号量

释放和获取: 计数型信号量的释放和获取与二值信号量相同
应用:

taskENTER_CRITICAL(); //进入临界区
MutexSemaphore=xSemaphoreCreateMutex();  
taskEXIT_CRITICAL(); //退出临界区

void task1 (void )
{
xSemaphoreTake(MutexSemaphore,portMAX_DELAY); //获取互斥信号量
...............
xSemaphoreGive(MutexSemaphore); //释放信号量
}

void task2 (void )
{
xSemaphoreTake(MutexSemaphore,portMAX_DELAY); //获取互斥信号量
...............
xSemaphoreGive(MutexSemaphore); //释放信号量
}

4:递归互斥信号量

递归互斥信号量可以看作是一个特殊的互斥信号量,已经获取了互斥信号量的任务就不能
再次获取这个互斥信号量,但是递归互斥信号量不同,已经获取了递归互斥信号量的任务可以
再次获取这个递归互斥信号量,而且次数不限!

要使用递归互斥信号量的话宏 configUSE_RECURSIVE_MUTEXES 必须为 1!
创建:

函数名 原型 功能
xSemaphoreCreateRecursiveMutex() SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void ) 使用动态方法创建递归互斥信号量。
xSemaphoreCreateRecursiveMutexStatic() SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer ) 使用静态方法创建递归互斥信号量

释放和获取: 计数型信号量的释放和获取与二值信号量相同
应用:

SemaphoreHandle_t RecursiveMutex; //递归互斥信号量句柄
//某个任务中创建一个递归互斥信号量
void vATask( void * pvParameters )
{
//没有创建创建递归互斥信号量之前不要使用!
RecursiveMutex = xSemaphoreCreateRecursiveMutex();  //创建递归互斥信号量
for( ;; )
{
/************任务代码**************/
}
}
//任务调用的使用递归互斥信号量的功能函数。
void vAFunction( void )
{
/**********其他处理代码*****************/
if( xMutex != NULL )
{
//获取递归互斥信号量,阻塞时间为 10 个节拍
if( xSemaphoreTakeRecursive( RecursiveMutex, 10 ) == pdTRUE )
{
/***********其他处理过程*************/
//这里为了演示,所以是顺序的获取递归互斥信号量,但是在实际的代码中肯定
//不是这么顺序的获取的,真正的代码中是混合着其他程序调用的。
xSemaphoreTakeRecursive( RecursiveMutex, ( TickType_t ) 10 );
xSemaphoreTakeRecursive( RecursiveMutex, ( TickType_t ) 10 );
//任务获取了三次递归互斥信号量,所以就得释放三次!
xSemaphoreGiveRecursive( RecursiveMutex);
xSemaphoreGiveRecursive( RecursiveMutex);
xSemaphoreGiveRecursive( RecursiveMutex);
//递归互斥信号量释放完成,可以被其他任务获取了
}
else
{
/**********递归互斥信号量获取失败***********/
}
}
}

猜你喜欢

转载自blog.csdn.net/ZenNaiHeQiao/article/details/83749885