一、信号量简介
- 信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。信号量中存在计数值,计数值>0时表示信号量有资源
- 信号量仅存放数值,无法存放其他数据;释放信号量,不可阻塞,计数值++,计数值最大时,返回失败;获取信号量,计数值–,当没有资源时,可阻塞
二、 二值信号量
2.1 二值信号量简介
- 二值信号量的本质是一个长度为1的队列,该队列就只有空和满两种状态(0,1),这就是二值
- 二值信号量通常用于互斥访问(条件判断只有一种情况满足)或任务同步(任务按前后顺序执行
- 下面是二值信号量相关的API函数
- 使用二值信号量的过程:创建二值信号量-释放二值信号量(入队)-获取二值信号量(出队)
xSemaphoreCreatBinary();
xSemaphoreCreatBinaryStatic();
xSemaphoreGive();
xSemaphoreGiveFromISR();
xSemaphoreTake();
xSemaphoreTakeFromISR();
- 动态创建二值信号量,本质上创建信号量就是创建长度为1的队列
SemaphoreHandle_t xSemaphoreCreateBinary();
#define xSemaphoreCreateBinary() xQueueGenericCreate(1,队列项大小,创建类型)
BaseType_t xSemaphoreGive(xSemaphore)
#define xSemaphoreGive(xSemaphore) xQueueGenericSend(xSemaphore,NULL,semGIVE_BLOCK_TIME,queueSEND_TO_BACK)
BaseType_t xSemaphoreTake(xSemaphore,xBlockTime)
2.2 二值信号量实验
- 设计三个任务,start_task:创建task1和task2。task1:按键扫描,当检测到按键key0按下时,释放二值信号量。task2:获取二值信号量
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t start_task_handle;
#define TASK1_STACK_SIZE 128
#define TASK1_PRIO 2
TaskHandle_t task1_handle;
#define TASK2_STACK_SIZE 128
#define TASK2_PRIO 3
TaskHandle_t task2_handle;
void task1( void * pvParameters )
{
uint8_t KeyNum = 0;
BaseType_t err;
while(1)
{
KeyNum = Key_GetNum();
if(KeyNum == 0)
{
err = xSemaphoreGive(semphopre_handle);
}
vTaskDelay(10);
}
}
void task2( void * pvParameters )
{
while(1)
{
xSemaphoreTake(semphopre_handle,portMAX_DELAY);
}
}
void Start_task( void * pvParameters )
{
taskENTER_CRITICAL();
xTaskCreate(task1,
"task1",
TASK1_STACK_SIZE,
NULL,
TASK1_PRIO,
&task1_handle
);
xTaskCreate(task2,
"task2",
TASK2_STACK_SIZE,
NULL,
TASK2_PRIO,
&task2_handle
);
vTaskDelete(start_task_handle);
taskEXIT_CRITICAL();
}
QueueHandle_t semphopre_handle;
void freertos_demo()
{
semphopre_handle= xSemaphoreCreateBinary();
xTaskCreate(Start_task,
"Start_task",
START_TASK_STACK_SIZE,
NULL,
START_TASK_PRIO,
&start_task_handle
);
vTaskStartScheduler();
}
三、计数型信号量
3.1 计数型信号量简介
- 计数型信号量相当于队列长度大于1的队列,可以容纳多个资源,队列长度在创建信号量时确定
- 计数型信号量适用于事件计数-事件发生,释放计数型信号量(计数值+1),其他任务获取信号量(计数值-1),创建时初始计数值设置为0、同时适用于资源管理-信号量表示有效的资源数目
- 使用流程:创建计数型信号量(初始为0)-释放信号量(+1)-获取信号量
- 下面是计数型信号量的相关API函数
- 计数型信号量的释放和获取与二值信号量一致
xSemaphoreCreateCounting();
xSemaphoreCreateCountingStatic();
xSemaphoreGetCount();
xSemaphoreGive();
xSemaphoreGiveFromISR();
xSemaphoreTake();
xSemaphoreTakeFromISR();
xSemaphoreCreateCounting(uxMaxCount,uxInitialCount);
uxSemaphoreGetCount(xSemaphore);
3.2 计数型信号量实验
- 设计三个任务,start_task:创建task1和task2。task1:按键扫描,当检测到按键key0按下时,释放(+1)计数型信号量量。task2:每过一秒获取(-1)一次计数型信号量
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t start_task_handle;
#define TASK1_STACK_SIZE 128
#define TASK1_PRIO 2
TaskHandle_t task1_handle;
#define TASK2_STACK_SIZE 128
#define TASK2_PRIO 3
TaskHandle_t task2_handle;
void task1( void * pvParameters )
{
uint8_t KeyNum = 0;
BaseType_t err;
while(1)
{
KeyNum = Key_GetNum();
if(KeyNum == 0)
{
err = xSemaphoreGive(count_semphopre_handle);
}
vTaskDelay(10);
}
}
void task2( void * pvParameters )
{
while(1)
{
xSemaphoreTake(count_semphopre_handle,portMAX_DELAY);
vTaskDelay(1000);
}
}
void Start_task( void * pvParameters )
{
taskENTER_CRITICAL();
xTaskCreate(task1,
"task1",
TASK1_STACK_SIZE,
NULL,
TASK1_PRIO,
&task1_handle
);
xTaskCreate(task2,
"task2",
TASK2_STACK_SIZE,
NULL,
TASK2_PRIO,
&task2_handle
);
vTaskDelete(start_task_handle);
taskEXIT_CRITICAL();
}
QueueHandle_t count_semphopre_handle;
void freertos_demo()
{
count_semphopre_handle= xSemaphoreCreateCounting(100,0);
xTaskCreate(Start_task,
"Start_task",
START_TASK_STACK_SIZE,
NULL,
START_TASK_PRIO,
&start_task_handle
);
vTaskStartScheduler();
}
四、互斥信号量
4.1 互斥信号量简介
- 互斥信号量是一个拥有优先级继承的二值信号量,适用于需要互斥访问的应用中
- 优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞(高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级)
- 优先级继承并不能完全消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响,只是将低优先级抬高
- 互斥信号量不能用于中断服务函数中
- 使用互斥信号量流程:configUSE_MUTEXES置1,创建互斥信号量-获取信号量-释放信号量(创建互斥信号量时会主动释放一次信号量)
- 互斥信号量相关API函数
xSemaphoreCreateMutex();
xSemaphoreCreateMutexStatic();
xSemaphoreGive();
xSemaphoreTake();
xSemaphoreCreateMutex();