1. 轮询的方式
实例如下:
A: B:
while(flag != 0); while(flag != 1);
{ {
临界区代码; 临界区代码;
} }
flag = 1; flag = 0;
如上图所示:因为进程A执行完成后会将flag置为1,当flag为1时,进程B可以执行,进程B执行完成后flag置为0,进程A重新执行。但是如果A进程执行完成,flag置为1后,B进程没有执行,那么flag就不会置为0,A进程将永远页不能继续执行了。所以轮询的方法不能实现锁。
2. 标记的方式
A: B:
flag[0] = true; flag[1] = true;
while(flag[1] == true); while(flag[0] == true);
{ {
临界区代码; 临界区代码;
} }
flag[0] = flase; flag[1] = false;
如上图所示: 当进程A执行时将flag[0]置为true,并执行临界区代码;当进程B执行时将flag[1]置为true,并执行临界区代码。
但是当A进程将flag[0]置为true时,进程时间片到了,切换到B进程执行,B进程将flag[1]置为true,那么A,B两个进程都将被阻塞。所以标记的方法不能实现锁。
实现锁的方式:
1. 轮询 + 标记
A: B:
flag[0] = true; flag[1] = true;
turn = 1; turn = 0;
while(flag[1] && turn == 1); while(flag[0] && turn == 0);
{ {
临界区代码; 临界区代码;
} }
flag[0] = false; flag[1] = false;
如上图所示:turn = 0 = 1矛盾,所以进程A和进程B同时只能有一个进程执行。
2. 原子操作
int lock(int *a)
{
int tmp = *a;
*a = true;
return tmp;
}
while(lock(&a));
{
临界区代码;
}
a = false;
如上图所示:每次调用调用临界区代码之前调用lock函数。如果调用lock时,锁没有被使用,则返回false,并将锁置为1。其它进程调用lock时,发现锁的值为1,则会进行等待锁的释放。但是这里需要对lock函数进行保护。
通过硬件将lock函数变为一个原子操作即可实现锁机制。(具体硬件怎样去实现,不太清楚)。