1、互斥信号量
互斥信号量其实就是一个拥有优先级继承的二值信号量,多用于不同任务间对共享资源的互斥访问。
2、互斥信号量降低优先级翻转的影响
当一个互斥信号量正在被任务L使用,而此时有个任务H也尝试获取这个互斥信号量的话就会被阻塞。不过这个任务H会将任务L的优先级提升到与自己相同的优先级, 这个过程就是优先级继承。优先级继承尽可能的降低了高优先级任务处于阻塞态的时间,并且将已经出现的“优先级翻转”的影响降到最低。
序号 | 说明 |
---|---|
(1) | 任务H和任务M为阻塞状态,等待某一事件发生,此时任务L正在运行 |
(2) | 此时任务L要访问共享资源,需要获取互斥锁,同时系统将L的优先级拉至与H一样 |
(3) | 任务L成功获取互斥锁,此时锁已被占用,任务L开始访问共享资源 |
(4) | 时间片轮循时间到,此时任务H就绪,开始运行 |
(5) | 任务H开始运行 |
(6) | 此时任务H要访问共享资源,因此需要获取锁,但此时锁未释放,因此任务H阻塞等待互斥锁释放 |
(7) | 由于L与H此时优先相同,且大于M,所以任务L继续运行 |
(8) | 任务L释放互斥锁 |
(9) | 任务H获取到互斥锁资源,解除阻塞开始运行,此时L的优先级又回到原值 |
(10) | 任务H运行完毕,进入阻塞 |
(11) | 任务M此时是就绪列表里面优先级最高的开始运行 |
(12) | 任务M运行完毕,进入阻塞 |
(13) | 任务L开始新一轮的运行 |
3、互斥信号量的API函数
3.1、创建
| |
| |
参数 | 说明 |
void | 空 |
返回值 | 说明 |
NULL | 创建互斥信号量失败 |
其他值 | 创建互斥信号量成功 |
3.2、释放
与二值信号量一样,请参考二值信号量释放函数
3.3、获取
与二值信号量一样,请参考二值信号量释放函数
4、实验
4.1、实验设计
实验设计跟“优先级翻转”章节流程一样,只是将“二值信号量”换成了“互斥信号量”。
4.2、实验代码
//任务1
k_task_handle_t task1_handle; //任务1 句柄
#define TSK1_PRIO 2 //任务1 优先级
#define TASK1_STK_SIZE (1*512) //任务1 分配的堆栈大小
//任务2
k_task_handle_t task2_handle; //任务2 句柄
#define TSK2_PRIO 3 //任务2 优先级
#define TASK2_STK_SIZE (1*512) //任务2 分配的堆栈大小
//任务3
k_task_handle_t task3_handle; //任务3 句柄
#define TSK3_PRIO 4 //任务3 优先级
#define TASK3_STK_SIZE (1*512) //任务3 分配的堆栈大小
//开始任务
k_task_handle_t start_task_handle; //开始任务 句柄
#define START_TSK_PRIO 1 //开始任务 优先级
#define START_TSK_STK_SIZE 1024 //开始任务 分配的堆栈大小
#define TEST_TIME_QUANTA 100
k_mutex_handle_t g_Mutex; //互斥量
void task1(void)
{
uint32_t i = 0;
while(1)
{
csi_kernel_mutex_lock(g_Mutex,portMAX_DELAY);
my_printf("Low task running!\r\n");
for(i=0;i<2000000;i++)
{
taskYIELD();
}
csi_kernel_mutex_unlock(g_Mutex);
csi_kernel_delay_ms(1000);
}
}
void task2(void)
{
while(1)
{
my_printf("Middle task running!\r\n");
csi_kernel_delay_ms(1000);
}
}
void task3(void)
{
while(1)
{
csi_kernel_delay_ms(500);
my_printf("High task Pend Semaphore\r\n");
csi_kernel_mutex_lock(g_Mutex, portMAX_DELAY);
my_printf("High task running!\r\n");
csi_kernel_mutex_unlock(g_Mutex);
csi_kernel_delay_ms(500);
}
}
void start_task(void)
{
//进入临界区
taskENTER_CRITICAL();
//创建互斥量
g_Mutex = csi_kernel_mutex_new();
if(g_Mutex == NULL)
{
printf("fail to create mutex.\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");
}
//创建task 3
csi_kernel_task_new((k_task_entry_t)task3, "task3", NULL, TSK3_PRIO, TEST_TIME_QUANTA, NULL, TASK3_STK_SIZE, &task3_handle);
if (task3_handle == NULL)
{
csi_kernel_sched_resume(0);
my_printf("Fail to create task 3!\r\n");
}
//删除开始任务
if(0 != csi_kernel_task_del(csi_kernel_task_get_cur()))
{
my_printf("Fail to delete start_task!\r\n");
}
else
{
my_printf("start_task is deleted!\r\n");
}
//退出临界区
taskEXIT_CRITICAL();
}
void freertos_demo(void)
{
my_printf("\r\n-->this is freertos task test demo!!!\r\n"); //print message
//系统初始化
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();
}
4.3、实验现象
-
Task 3(High task)很快就得到运行的机会,不会被Task 2(Middle task)耽误很长时间。