信号量的基本概念:
信号量是一种实现任务间通信的机制,可以实现任务之间同步或者临界资源的互斥访问,常用于协助一组相互竞争的任务来访问临界资源。信号量是一个非负整数,所以获取它的任务都会将整数减一,当该整数值为零时,所有试图获取他的任务都将处于阻塞态,通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数
0:表示没有积累下来的释放信号量的操作,且有可能有在此信号量上阻塞的任务
正值:表示有一个或者多个释放信号量的操作。
二值信号量:
二值信号量既可以用于临界资源访问也可以用于同步功能。二值信号量和互斥信号量非常相似,但是有一些细微的差别,互斥量有优先级继承机制,二值信号量没有这个机制,二值信号量更偏向于同步功能,互斥量更偏向于临界资源的访问。
用作同步时,信号量在创建后应被置为空,任务1获取信号量而进入阻塞,任务2在某种条件发生后释放信号量,于是任务1获得信号量进入就绪态,如果任务1的优先级最高,就会立即切换任务,从而达到两个任务的同步。可以将二值信号量看做是只有一个消息的消息队列,这个队列只能为满或者空。
计数信号量:
计数信号量用于计数,用于事件计数和资源管理,信号量的数值表示还有多少个事件没被处理,任务必须先获取信号量才能获取资源的访问权,当信号量的计数为零时 表示系统中没有可用资源。在使用完资源之后 要归信号量。
互斥信号量:
互斥信号量时特殊的二值信号量,适用于简单的互锁,保护临界资源。·创建后信号量的个数是满的,任务在使用临界资源时,先获取互斥信号量 让其他任务不能进入临界资源 保证临界资源的安全。
递归信号量:
递归信号量对于已获取递归互斥量的任务可以重复获取该递归信号量的值,任务成功获取几次递归互斥量就要返还几次,在此之前递归信号量都处于无效状态,其他任务无法获取,只有持有递归信号量的任务才能获取与释放。
二值信号量的运作机制:
计数信号量的运作机制:
创建信号量函数:
1.创建二值信号量:
xSemaphoreCreateBinary()用于创建一个二值信号量,并返回一个句柄。其实二值信号
量和互斥量都共同使用一个类型 SemaphoreHandle_t 的句柄。使 用 该 函数 创 建 的 二 值信 号 量 是 空的 , 在 使 用函 数 xSemaphoreTake()获取之前必须先调用函数 xSemaphoreGive()释放后才可以获取。所有 FreeRTOS 的对象在创建的时候都默认使用动态内存 分配方案。
//二值信号量创建实例
SemaphoreHandle_t xSemaphore =NULL;
void vATask(void * pvParameters)
{
//创建一个信号量
xSemaphore=xSemphoreCreateBinary();
if(xSemaphore==NULL)
{
//内存不足 创建失败
}
else
{
/*信号量现在可以使用,句柄存在变量 xSemaphore 中
这个时候还不能调用函数 xSemaphoreTake()来获取信号量
因为使用 xSemaphoreCreateBinary()函数创建的信号量是空的
在第一次获取之前必须先调用函数 xSemaphoreGive()先提交*/
}
}
2.创建计数信号量:
xSemaphoreCreateCounting ()用于创建一个计数信号量。要想使用该函数必须在
FreeRTOSConfig.h 中把宏 configSUPPORT_DYNAMIC_ALLOCATION 定义为 1,即开启动
态内存分配。其实该宏在 FreeRTOS.h 中默认定义为 1,即所有 FreeRTOS 的对象在创建的
时候都默认使用动态内存分配方案。
void vATask( void * pvParameters )
{
SemaphoreHandle_t xSemaphore;
/* 创建一个计数信号量, 用于事件计数 */
xSemaphore = xSemaphoreCreateCounting( 5, 5 );
if ( xSemaphore != NULL ) {
/* 计数信号量创建成功 */
}
}
信号量删除函数vSemaphoreDelete():
vSemaphoreDelete()用于删除一个信号量,包括二值信号量,计数信号量,互斥量和递
归互斥量。
信号量释放函数:
FreeRTOS 提供了信号量释放函数,每调用一次该函数就释放一个信号量,无论是你的信号量是二值信号量还是计数信号量,都要注意可用信号量的范围,当用作二值信号量的时候,必须确保其可用值在 0~1 范围内;而用作计 数信号量的话,其范围是由用户在创建时指定 uxMaxCount,其最大可用信号量不允许超出 uxMaxCount,这代表我们不能一直调用信号量释放函数来释放信号量,其实一直调用也是无法释放成功的.
//使用实例
static void Send_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
while (1) {
/* K1 被按下 */
if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ) {
xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量
if ( xReturn == pdTRUE )
printf("BinarySem_Handle 二值信号量释放成功!\r\n");
else
printf("BinarySem_Handle 二值信号量释放失败!\r\n");
}
/* K2 被按下 */
if ( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON ) {
xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量
if ( xReturn == pdTRUE )
printf("BinarySem_Handle 二值信号量释放成功!\r\n");
else
printf("BinarySem_Handle 二值信号量释放失败!\r\n");
}
vTaskDelay(20);
}
}
信号量获取函数:
与释放信号量对应的是获取信号量,我们知道,当信号量有效的时候,任务才能获取
信号量,当任务获取了某个信号量的时候,该信号量的可用个数就减一,当它减到 0 的时
候,任务就无法再获取了,并且获取的任务会进入阻塞态.
释放信号量实际上是一次消息出队操作,阻塞时间由用户指定
xBlockTime,当有任务试图获取信号量的时候,当且仅当信号量有效的时候,任务才能读
获取到信号量。如果信号量无效,在用户指定的阻塞超时时间中,该任务将保持阻塞状态
以等待信号量有效。当其它任务或中断释放了有效的信号量,该任务将自动由阻塞态转移
为就绪态。当任务等待的时间超过了指定的阻塞时间,即使信号量中还是没有可用信号量,
任务也会自动从阻塞态转移为就绪态。
static void Receive_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
while (1) {
//获取二值信号量 xSemaphore,没获取到则一直等待
xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
portMAX_DELAY); /* 等待时间 */
if (pdTRUE == xReturn)
printf("BinarySem_Handle 二值信号量获取成功!\n\n");
LED1_TOGGLE;
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)