1、二值信号量和计数信号量
二值信号量 | |
概念 |
|
应用场景 |
|
阻塞 |
|
计数信号量 | |
概念 |
|
应用场景 |
|
阻塞 |
|
2、相关API函数
2.1、创建
| |
| |
参数 | 说明 |
void | 空 |
返回值 | 说明 |
NULL | 创建二值信号量失败 |
其他值 | 创建二值信号量成功 |
| |
| |
参数 | 说明 |
uxMaxCount | 计数信号最大值,当信号量值等于此值的时候释放信号量会失败 |
uxInitialCount | 计数信号量初始值 |
返回值 | 说明 |
NULL | 计数型信号量创建失败 |
其他值 | 计数型信号量创建成功,返回计数型信号量句柄 |
2.2、释放
| |
| |
参数 | 说明 |
xSemaphore | 待释放信号量。该参数是一个 SemaphoreHandle_t 类型的变量,并且在使用前一定先创建。 |
返回值 | 说明 |
pdPASS | 信号量释放成功 |
pdFAIL | 信号量释放失败,如果信号量没有被第一时间获取,再次释放信号量时就会失败 |
| |
| |
参数 | 说明 |
xSemaphore | 待释放信号量。该参数是一个 SemaphoreHandle_t 类型的变量,并且在使用前一定先创建 |
pxHighPriorityWoken | 如果有多个任务等待获取信号量而进入阻塞态,调用该函数可以使任务解除阻塞态。 如果任务队列中存在优先级比解除阻塞态的任务优先级高,或者两者的优先级等同,那么 pxHighPriorityWoken 的值就会被设为 pdTRUE。如果 xpHighPriorityWoken 为 pdTRUE,则退出中断服务函数之前必须进行一次任务切换 |
返回值 | 说明 |
pdTRUE | 信号量释放成功 |
pdFAIL | 信号量释放失败,因为该信号量已经被释放,但还未被获取 |
2.3、获取
| |
| |
参数 | 说明 |
xSemaphore | 待获取的信号量 |
xBlockTime | 阻塞时间 |
返回值 | 说明 |
pdTRUE | 获取信号量成功 |
pdFAIL | 获取超时或者失败 |
| |
| |
参数 | 说明 |
xSemaphore | 待获取的信号量 |
pxHighPriorityWoken | 标记退出中断服务函数之前是否需要进行任务切换。该值由函数去设置,用户仅提供 存储的变量。如果 pxHighPriorityWoken 的值为 pdTRUE,则退出中断函数前必须进行一次任务切换 |
返回值 | 说明 |
pdPASS | 获取信号量成功 |
pdFALSE | 获取信号量失败 |
3、实验
3.1、实验设计
-
创建一个开始任务,在开始任务里面,创建二值信号量、task 1和task 2两个任务后,删除开始任务;
-
task 1运行10次后,释放一个信号量;
-
task 2一直获取该信号量,获取到后,打印信息;
3.2、实验程序
k_task_handle_t task1_handle; //task 1 句柄
#define TSK1_PRIO 3 //task 1 优先级
#define TASK1_STK_SIZE (1*1024) //task 1 分配的堆栈大小
k_task_handle_t task2_handle; //task 2 句柄
#define TSK2_PRIO 2 //task 2 优先级
#define TASK2_STK_SIZE (1*1024) //task 2 分配的堆栈大小
k_task_handle_t start_task_handle; //start task 句柄
#define START_TSK_PRIO 1 //start task 优先级
#define START_TSK_STK_SIZE (1*1024) //start task 分配的堆栈大小
#define TEST_TIME_QUANTA 100
k_sem_handle_t g_usSem; //信号量
void task1(void)
{
uint8_t count = 0;
while(1)
{
count++;
my_printf("task 1 run %d times!!!\r\n", count);
if(count == 10)
{
if(0 != csi_kernel_sem_post(g_usSem))
{
my_printf("---task 1 give sem fail!!!\r\n");
}
else
{
my_printf("---task 1 give sem sucess!!!\r\n");
}
count = 0;
}
csi_kernel_delay_ms(1000);
}
}
void task2(void)
{
while(1)
{
if(0 != csi_kernel_sem_wait(g_usSem, -1))
{
my_printf("task 2 take sem fail!!!\r\n");
}
else
{
my_printf("task 2 take sem sucess,task 2 is working now!!!\r\n");
}
}
}
void start_task(void)
{
//进入临界区
taskENTER_CRITICAL();
//创建二值信号量
g_usSem = csi_kernel_sem_new(1, 0);
if (g_usSem == NULL)
{
printf("fail to create semaphore.\n");
}
//创建task 1
csi_kernel_task_new((k_task_entry_t)task1,
"task1",
NULL,
TSK1_PRIO,
TEST_TIME_QUANTA,
NULL,
TASK1_STK_SIZE,
&task1_handle);
if (task1_handle == NULL)
{
csi_kernel_sched_resume(0);
my_printf("Fail to create task 1!\r\n");
}
//创建task 2
csi_kernel_task_new((k_task_entry_t)task2,
"task2",
NULL,
TSK2_PRIO,
TEST_TIME_QUANTA,
NULL,
TASK2_STK_SIZE,
&task2_handle);
if (task2_handle == NULL)
{
csi_kernel_sched_resume(0);
my_printf("Fail to create task 2!\r\n");
}
//删除开始任务
if(0 != csi_kernel_task_del(csi_kernel_task_get_cur()))
{
my_printf("Fail to delete start_task!\r\n");
}
//退出临界区
taskEXIT_CRITICAL();
}
void freertos_demo(void)
{
my_printf("\r\n-->this is freertos task test demo!!!\r\n");
//系统初始化
csi_kernel_init();
//创建开始任务
csi_kernel_task_new((k_task_entry_t)start_task,
"start_task",
0,
START_TSK_PRIO,
0,
0,
START_TSK_STK_SIZE,
&start_task_handle);
//任务调度开始
csi_kernel_start();
}
3.3、实验现象
-
start task在创建后,创建好task 1 task 2即被删除
-
初始阶段task 1运行, task 2由于此时获取到信号量还没有释放,处于堵塞状态
-
task 1运行10次后,释放一个信号量。task 2获取到信号量后,执行了打印动作
-
此时task 2运行受到了信号量的控制,未获取信号量前即堵塞,充分释放了CPU的使用权