进程互斥锁的初步实现(下)

问题

内核中如何实现任务的阻塞?

把执行队列中的任务放入等待队列。

再论任务状态

由互斥锁触发的内核操作

当任务获取锁失败

  • 将当前任务移入等待队列 (进入阻塞态)
  • 调度下一任务执行

当互斥锁被标记为空闲

  • 将等待队列中的任务移入就绪队列 (脱离阻塞态)

互斥锁与任务调度一

互斥锁与任务调度二

互斥锁与任务调度三

互斥锁与任务调度

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 并行执行。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值