软件实现
单标志法
int turn = 0; // 表示当前允许进入临界区的进程号
// turn 表示的是谦让
P0 进程:
// 进入区
while (turn != 0); Ⅰ // turn 不是0代表当前不该自己进入临界区,那么就一直卡在while循环
// 临界区
critical section; Ⅱ
// 退出区
turn = 1; Ⅲ // 自己已经完成了对临界资源的使用,把使用权交给另一个进程
// 剩余区
remainder section; Ⅳ
P1 进程:
// 进入区
while (turn != 1); Ⅴ // turn 不是1代表当前不该自己进入临界区,那么就一直卡在while循环
// 临界区
critical section; Ⅵ
// 退出区
turn = 0; Ⅶ // 自己已经完成了对临界资源的使用,把使用权交给另一个进程
// 剩余区
remainder section; Ⅷ
这个方法是交替访问临界区资源的,所以一旦某个进程不再访问临界区资源,那么就会导致另一个进程也不能访问临界区资源,这样就会造成资源的浪费。违背:空闲让进,让权等待
双标志先检查法
先检查后上锁:
bool flag[2]; // 表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; // 刚开始两个进程都不想进入临界区
P0 进程:
// 进入区
while (flag[1]); Ⅰ // 如果 P1 想要进入, P0 进程就会卡死在这里
flag[0] = true; Ⅲ // P0 表达自己想要使用临界区
// 临界区
critical section;
// 退出区
flag[0] = false; // P0 已经访问完了临界区资源,更改意愿为:不想访问临界区
// 剩余区
remainder section;
P1 进程:
// 进入区
while (flag[0]); Ⅱ // 如果 P0 想要进入, P1 进程就会卡死在这里
flag[1] = true; Ⅳ // P1 表达自己想要使用临界区
// 临界区
critical section;
// 退出区
flag[1] = false; // P1 已经访问完了临界区资源,更改意愿为:不想访问临界区
// 剩余区
remainder section;
按照 Ⅰ,Ⅱ,Ⅲ,Ⅳ的顺序执行,则会导致 flag[0] = true, flag[1] = true;
两个进程都会进入临界区,违背:忙则等待,让权等待;原因在于 “检查” 和 “上锁” 两个操作不能一气呵成。
双标志后检查法
先上锁后检查:
bool flag[2]; // 表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; // 刚开始两个进程都不想进入临界区
P0 进程:
// 进入区
flag[0] = true; Ⅰ // P0 表达自己想要使用临界区
while (flag[1]); Ⅲ // 如果 P1 想要进入, P0 进程就会卡死在这里
// 临界区
critical section;
// 退出区
flag[0] = false; // P0 已经访问完了临界区资源,更改意愿为:不想访问临界区
// 剩余区
remainder section;
P1 进程:
// 进入区
flag[1] = true; Ⅱ // P1 表达自己想要使用临界区
while (flag[0]); Ⅳ // 如果 P0 想要进入, P1 进程就会卡死在这里
// 临界区
critical section;
// 退出区
flag[1] = false; // P1 已经访问完了临界区资源,更改意愿为:不想访问临界区
// 剩余区
remainder section;
按照 Ⅰ,Ⅱ,Ⅲ,Ⅳ的顺序执行,则会导致 flag[0] = true, flag[1] = true;
两个进程都无法进入临界区,违背:空闲让进,有限等待,让权等待,导致饥饿的现象
Pesterson 算法
单标志法 + + + 双标志后检查法:
bool flag[2];
int turn = 0;
P0 进程:
// 进入区
flag[0] = true; // 表达自己要用的意愿
turn = 1; // 愿意先让给你用
while (flag[1] && turn == 1); // 对方也想用并且最后是自己谦让的话就让对方用,自己卡死
// 临界区
critical section;
// 退出区
flag[0] = false; // 自己用完了,进入圣人模式
// 剩余区
remainder section;
P1 进程:
// 进入区
flag[1] = true; // 表达自己要用的意愿
turn = 0; // 愿意先让给你用
while (flag[0] && turn == 0); // 对方也想用并且最后是自己谦让的话就让对方用,自己卡死
// 临界区
critical section;
// 退出区
flag[1] = false; // 自己用完了,进入圣人模式
// 剩余区
remainder section;
不遵循:让权等待
硬件实现
中断屏蔽方法
...
关中断;
临界区;
开中断;
...
TestAndSet(TS指令/TSL指令)
// lock = true; 代表上锁
// lock = false; 表示未上锁
bool TestAndSet(bool *lock){
bool old;
old = *lock; // old用来存放lock原来的值
*lock = true; // 无论是否上锁,都上锁
return old; // 返回old原来的值
}
// 用 TestAndSet 指令实现互斥的逻辑
while (TestAndSet(&lock)); // 上锁并检查
临界区代码段...
lock = false; // 解锁
剩余区代码段...
不满足:让权等待
Swap指令(XCHG指令)
// Swap 指令的作用是交换两个变量的值
Swap (bool *a, bool *b){
bool temp;
temp = *a;
*a = *b;
*b = temp;
}
// 以下是用 Swap 指令实现互斥的算法逻辑
// lock = true; 代表上锁
// lock = false; 表示未上锁
bool old = true;
while (old == true)
Swap(&lock, &old);
临界区代码段...
lock = false;
剩余区代码段...
不满足:让权等待