互斥的实现往往用到原子操作,而原子操作需要硬件的支持,那么如何用软件实现互斥呢?
其思想是采用变量控制进程访问临界区
分析两个进程下的场景:
①采用一个变量且判断依据相同,例如:if(flag),并发时锁不住。
若不同判断依据,例如:进程a while(flag==1) 进程b while(flag==2),则导致只能一个进程先执行,另一个后执行(单标志法的缺陷)。
②所以此算法使用两个变量flag[0]和flag[1]用于上锁(限制对方执行),使两个进程可以互斥访问且都有资格首先执行。
确定了锁变量的数量 此时还有问题那就是先上锁还是先检查?
|-如果先上锁后检查,并发时有死锁的可能。因为两个进程同时分别修改了flag[0],flag[1] 然后同时开始while检查,结果死循环。(双标志先检查法的缺陷)
|-如果先检查后上锁,并发时锁不住。因为两个进程检查时都没有锁,然后都进入了临界区。(双标志后检查法的缺陷)
Peterson采用了双标志后检查法+共享变量,因为如果双标志前检查法+共享变量还会有单标志法的缺陷
定义一个共享变量 turn 主要用于防止死锁,因为turn每个时刻都只有一种状态,所以至少会有一个进程执行。
由于使用while循环实现的(占用CPU),所以未能满足让权等待原则
boolean flag[2];
int turn;
void procedure0()
{
while(true)
{
flag[0]=true;
turn=1;
while(flag[1]&&turn==1) /*若flag[1]为false,P0就进入临界区;若flag[1]为tureP0循环等待,只要P1退出临界区,P0即可进入*/
{
/* donothing*/
}
visit();/*访问临界区*/
flag[0]=false;/*访问临界区完成,procedure0释放出临界区*/
/*remainder section*/
}
}
void procedure1()
{
while(true)
{
flag[1]=true;
turn=0;
while(flag[0]&&turn==0)
{
/* donothing*/ ;
}
visit();/*访问临界区*/
flag[1]=false;/*访问临界区完成,procedure1释放出临界区*/
/*remainder section*/
}
}
void main()
{
flag[0]=flag[1]=false;
/*start procedure0 and procedure1*/ ;
}