目录
1.semaphore的基本概念
信号量用于任务与任务之间,任务与中断之间的同步。也可以对临界资源的互斥访问。
2.semaphore的特点
1)信号量是一个非负整数;
2)可用于任务之间的同步或临界资源的访问;
3)任务在无法获取到信号量时,会挂起当前的任务;
4)用于同步时,信号量创建后设置为空,任务1获取信号量而阻塞,那么任务将会挂到该信号量阻塞的等待列表中,当任务2释放信号量时,会进行任务调度,那么任务1获取信号量而会进入就绪序列,如果任务1的优先级最高,那么任务1会得到立即执行;如果任务1相对于任务2的优先级低,那么任务2会执行结束后,任务调度到任务1的优先级最高时,任务1才会得到执行。
4)释放信号量,信号量值+1,获取信号量,信号量值-1;
3.semaphore的运行机制
任何任务都可以从创建的信号量中获取信号量值,获取成功则会根据当前任务和就绪任务列表的优先级来确定哪个任务执行,如果获取信号量失败,则将当前任务挂到阻塞任务的列表中。
4.semaphore的应用场景
1)任务间的同步;
2)临界资源的互斥访问。
5.demo分析
#include "APPTaskDef.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "event_groups.h"
#include "semphr.h"
#define START_TASK_PRIO 1
#define START_STACK_SIZE 128
TaskHandle_t startTask_handler; //开始任务句柄
static void start_task(void *param);
#define GET_SEM_TASK_PRIO 3
#define GET_SEM_TASK_STACK_SIZE 128
TaskHandle_t get_sem_task_handler; //任务1句柄
static void get_sem_task(void *pvPara);
#define SET_SEM_TASK_PRIO 2
#define SET_SEM_TASK_STACK_SIZE 128
TaskHandle_t set_sem_task_handler; //任务2句柄
static void set_sem_task(void *pvPara);
void APP_task(void)
{
xTaskCreate((TaskFunction_t)start_task,
(const char *)"start_task",
(uint16_t)START_STACK_SIZE,
NULL,
(UBaseType_t)START_TASK_PRIO,
(TaskHandle_t *)&startTask_handler);
vTaskStartScheduler(); //开启任务调度
}
static void start_task(void *param)
{
SemaphoreHandle_t key_sem = xSemaphoreCreateCounting(10, 0);//创建一个计数信号量
taskENTER_CRITICAL(); //进入临界区
//创建获取event的任务
xTaskCreate((TaskFunction_t )get_sem_task,
(const char* )"get_sem",
(uint16_t )GET_SEM_TASK_STACK_SIZE,
(void* )key_sem,
(UBaseType_t )GET_SEM_TASK_PRIO,
(TaskHandle_t* )&get_sem_task_handler);
//创建设置event的任务
xTaskCreate((TaskFunction_t )set_sem_task,
(const char* )"set_sem",
(uint16_t )SET_SEM_TASK_STACK_SIZE,
(void* )key_sem,
(UBaseType_t )SET_SEM_TASK_PRIO,
(TaskHandle_t* )&set_sem_task_handler);
vTaskDelete(startTask_handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
/*
创建task0,不调用vTaskDelay();即不会引起任务调度,
为大致限定任务的执行时间,用delay_xms(10);这个函数不会引起任务调度,只是CPU在空等
*/
static void set_sem_task(void *param)
{
u8 key_value = 0;
//引用key sem
SemaphoreHandle_t key_sem = (SemaphoreHandle_t)param;
uint8_t sem_count = 0;
int times = 0;
while(1){
if(key_sem != NULL){
key_value = KEY_Scan(0);
switch(key_value){
/*
case KEY0_PRESS:
xEventGroupSetBits(key_event, EVENTBIT_0);
printf("KEY0 press\r\n");
break;
case KEY1_PRESS:
xEventGroupSetBits(key_event, EVENTBIT_1);
printf("KEY1 press\r\n");
break;
*/
case KEY_UP_PRESS:
xSemaphoreGive(key_sem);
sem_count = uxSemaphoreGetCount(key_sem);
printf("give a sem succeed\r\n");
printf("cur sem count is %d\r\n", sem_count);
printf("--------------------------------------------------------------\r\n");
break;
default:
break;
}
LED0 = ~LED0;
delay_ms(100);
}
delay_xms(10);
}
}
/*
创建task0,不调用vTaskDelay();即不会引起任务调度,
为大致限定任务的执行时间,用delay_xms(10);这个函数不会引起任务调度,只是CPU在空等
*/
static void get_sem_task(void *param)
{
EventBits_t EventValue;
uint8_t sem_count;
//引用key event
SemaphoreHandle_t key_sem = (SemaphoreHandle_t)param;
while(1){
xSemaphoreTake(key_sem, portMAX_DELAY);
sem_count = uxSemaphoreGetCount(key_sem);
printf("receive semaphore succeed!\r\n");
printf("cur sem count is %d\r\n", sem_count);
printf("--------------------------------------------------------------\r\n");
LED1 = ~LED1;
delay_xms(10);
}
}
任务1通过按键发送同步信号量,任务2获取信号量达到同步任务1的操作。在发送和获取信号量的同时可以获取信号量的当前值:uxSemaphoreGetCount(key_sem);