信号量是一种实现任务间通信的机制,可以实现任务之间同步或者临界资源的互斥访问,常用于协助一组相互竞争的任务来访问临界资源。信号量是一个非负整数,所以获取它的任务都会将整数减一,当该整数值为零时,所有试图获取他的任务都将处于阻塞态,通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数
0:表示没有积累下来的释放信号量的操作,且有可能有在此信号量上阻塞的任务
正值:表示有一个或者多个释放信号量的操作。
二值信号量既可以用于临界资源访问也可以用于同步功能。二值信号量和互斥信号量非常相似,但是有一些细微的差别,互斥量有优先级继承机制,二值信号量没有这个机制,二值信号量更偏向于同步功能,互斥量更偏向于临界资源的访问。
用作同步时,信号量在创建后应被置为空,任务1获取信号量而进入阻塞,任务2在某种条件发生后释放信号量,于是任务1获得信号量进入就绪态,如果任务1的优先级最高,就会立即切换任务,从而达到两个任务的同步。可以将二值信号量看做是只有一个消息的消息队列,这个队列只能为满或者空。
计数信号量用于计数,用于事件计数和资源管理,信号量的数值表示还有多少个事件没被处理,任务必须先获取信号量才能获取资源的访问权,当信号量的计数为零时 表示系统中没有可用资源。在使用完资源之后 要归信号量。
互斥信号量时特殊的二值信号量,适用于简单的互锁,保护临界资源。·创建后信号量的个数是满的,任务在使用临界资源时,先获取互斥信号量 让其他任务不能进入临界资源 保证临界资源的安全。
递归信号量对于已获取递归互斥量的任务可以重复获取该递归信号量的值,任务成功获取几次递归互斥量就要返还几次,在此之前递归信号量都处于无效状态,其他任务无法获取,只有持有递归信号量的任务才能获取与释放。
1.创建二值信号量:
//二值信号量创建实例
SemaphoreHandle_t xSemaphore =NULL;
void vATask(void * pvParameters)
{
//创建一个信号量
xSemaphore=xSemphoreCreateBinary();
if(xSemaphore==NULL)
{
//内存不足 创建失败
}
else
{
/*信号量现在可以使用,句柄存在变量 xSemaphore 中
这个时候还不能调用函数 xSemaphoreTake()来获取信号量
因为使用 xSemaphoreCreateBinary()函数创建的信号量是空的
在第一次获取之前必须先调用函数 xSemaphoreGive()先提交*/
}
}
2.创建计数信号量:
void vATask( void * pvParameters )
{
SemaphoreHandle_t xSemaphore;
/* 创建一个计数信号量, 用于事件计数 */
xSemaphore = xSemaphoreCreateCounting( 5, 5 );
if ( xSemaphore != NULL ) {
/* 计数信号量创建成功 */
}
}
信号量删除函数vSemaphoreDelete():
//使用实例
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);
}
}
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;
}
}