【知识回顾】
临界区互斥(软件方法)
基本思想:进程通过while循环判断对方的FLAG是否为true(是true则死循环);若用完临界区后则修改自己的FLAG。
【典例】假设有2个线程(编号为0和1)需要去访问同一个共享资源,为避免竞争状态的问题,必须实现一种互斥机制,使得在任何时候只能有一个线程访问这个资源,假设有如下一段代码:
Bool flag[2];//flag数组,初始化为FALSE
Enter_Critical_Section(int my_thread_id,int other_thread_id){
While(flag[other_thread_id]==TRUE);//空循环语句
Flag[my_thread_id]=TRUE;
}
Exit_Critical_Section(int my_thread_id,int other_thread_id){
flag[my_thread_id]=FALSE;
}
当一个线程想要访问临界资源,就调用上述的这个两个函数,例如,线程0的代码可能是这样的:
Exit_Critical_Section(0,1); (这里题目的形参只是指0和1线程编号==)
使用这个资源;
Exit_Critical_Section(0,1);
做其他的事情;
(1)以上的这种机制能够实现资源互斥访问吗,为什么
【解析】
题目的Enter函数即双标志先检查法。
不能。考虑如下情形:
- 初始化时,flag数组的2个元素值均为FALSE.
- 线程0先执行,执行while循环语句时,由于flag[1]=FALSE,所以顺利结束,不会被卡住。假设这时来了一个时钟中断,打断了它的运行(即0进程未进行enter函数第二句)。
- 线程1去执行,执行while循环语句时,由于flag[0]为FALSE,所以顺序结束,不会被卡住,然后进入临界区。
- 后来当线程0再执行时,也进入临界区,这样就同时有2个线程在临界区。
总结:不能成功的根本原因是无法保证Enter_Critical_Section()函数执行的原子性,我们从上面的软件实现方法中可以看出,对于两个进程间的互斥,最主要的问题是标志的检查和修改不能作为一个整体来执行,因此容易导致无法保证互斥访问的问题。
(2)若把Enter_Critical_Section()函数中的2条语句互换一下位置,结果会如何?
【解析】互换位置后即变成双标志后检查法。
可能会出现死锁,考虑如下情形:
- 初始化时,flag数组的两个元素值均为FALSE。
- 线程0先执行,falg[0]为TRUE,假设这时来了个时钟中断,打断了它的运行
- 线程1去执行,flag[1]为TRUE,在执行while循环语句时,由于flag[0]=TRUE,所以在这个地方被卡住,直到时间片用完。
- 线程0再执行时,由于flag[1]为TRUE,它也在while循环语句的地方被卡住,因此这两个线程都无法执行下去,从而死锁。