问题
内核中如何实现任务的阻塞?
把执行队列中的任务放入等待队列。
再论任务状态
由互斥锁触发的内核操作
当任务获取锁失败
- 将当前任务移入等待队列 (进入阻塞态)
- 调度下一任务执行
当互斥锁被标记为空闲
- 将等待队列中的任务移入就绪队列 (脱离阻塞态)
互斥锁与任务调度一
互斥锁与任务调度二
互斥锁与任务调度三
互斥锁与任务调度
task.h
enum
{
WAIT,
NOTIFY
};
task.c
static void WaitingToReady()
{
while(Queue_Length(&gWaitingTask) > 0)
{
TaskNode* tn = (TaskNode*)Queue_Front(&gWaitingTask);
Queue_Remove(&gWaitingTask);
Queue_Add(&gReadyTask, (QueueNode*)tn);
}
}
static void RunningToWaiting()
{
if(Queue_Length(&gRunningTask) > 0)
{
TaskNode* tn = (TaskNode*)Queue_Front(&gRunningTask);
if(!IsEqual(tn, gIdleTask))
{
Queue_Remove(&gRunningTask);
Queue_Add(&gWaitingTask, (QueueNode*)tn);
}
}
}
void MtxSchedule(uint action)
{
if(IsEqual(action, NOTIFY))
{
WaitingToReady();
}
else if(IsEqual(action, WAIT))
{
RunningToWaiting();
ReadyToRunning();
CheckRunningTask();
Queue_Rotate(&gRunningTask);
gCTaskAddr = &((TaskNode*)Queue_Front(&gRunningTask))->task;
PrepareForRun(gCTaskAddr);
LoadTask(gCTaskAddr);
}
}
mutex.c
void SysEnterCritical(Mutex* mutex)
{
if(IsMutexValid(mutex))
{
if(mutex->lock)
{
PrintString("Move current to waitting status.\n");
MtxSchedule(WAIT);
}
else
{
mutex->lock = 1;
PrintString("Enter critical section, access critical resource.\n");
}
}
}
void SysExitCritical(Mutex* mutex)
{
if(IsMutexValid(mutex))
{
mutex->lock = 0;
PrintString("Notify all tasks to run again, critical resource is available.\n");
MtxSchedule(NOTIFY);
}
}
app.c
void AppMain()
{
RegApp("TaskA", TaskA, 255);
RegApp("TaskB", TaskB, 255);
//RegApp("TaskC", TaskC, 255);
//RegApp("TaskD", TaskD, 255);
}
void TaskA()
{
SetPrintPos(0, 12);
PrintString(__FUNCTION__);
PrintChar('\n');
g_mutex = CreateMutex();
PrintString("Mutex ID: ");
PrintIntHex(g_mutex);
PrintChar('\n');
EnterCritical(g_mutex);
for(i = 0; i < 50; i++)
{
SetPrintPos(8, 12);
PrintChar('A' + i % 26);
Delay(1);
}
ExitCritical(g_mutex);
}
void TaskB()
{
SetPrintPos(0, 16);
PrintString(__FUNCTION__);
EnterCritical(g_mutex);
while(1)
{
SetPrintPos(8, 16);
i++;
PrintChar('0' + i % 10);
Delay(1);
}
ExitCritical(g_mutex);
}
task.h 中定义了两个枚举值,它决定了互斥锁调度的策略;如若有两个或两个以上的任务访问临界资源时,后访问的任务会被阻塞,操作系统把它们放回等待队列;当临界资源可以被访问时,把等待队列的所有任务都放回就绪队列,等待调度。
TaskA 创建了互斥锁,并且想要访问临界资源 i,在它进入临界区时,TaskB 也想进入临界区,由于 TaskA 得到了互斥锁,所以 TaskB 被阻塞,被放入了等待队列;当 TaskA 退出临界区时,TaskB 从等待队列放入就绪队列,被调度执行,获取互斥锁,继续向下执行。
注意:不同时序决定了不同的运行结果,上述结果是 TaskA 创建了互斥锁,并且进入了临界区,TaskB 后进入临界区产生的;第二种情况是,TaskA 创建了互斥锁,但 TaskB 先进入临界区,那么 TaskA 将永远无法得到执行;第三种情况是,在 TaskA 还没完成创建互斥锁时,TaskB 就已经进入了临界区,此时 TaskB 就无法使用互斥锁,TaskA 和 Task B 并行执行。