先决条件–流程同步,进程间通信
为了获得这种互斥,有界等待和进展,已经实现了几种算法,其中之一是Dekker算法。要了解该算法,让我们首先了解关键部分问题的解决方案。
一个过程通常表示为:
do {
//entry section
critical section
//exit section
remainder section
} while (TRUE);
关键截面问题的解决方案必须确保满足以下三个条件:
- 互斥
- 进步
- 有限的等待
确保上述所有因素的解决方案之一是Peterson的解决方案。
另一个是Dekker的解决方案。 Dekker的算法是对关键截面问题的第一个证明正确的解决方案。它允许两个线程仅使用共享内存进行通信,而不会冲突地共享一次性使用的资源。它避免了天真转弯算法的严格替代,并且是最早发明的互斥算法之一。
尽管Dekker解决方案有很多版本,但最终版本或第5版是满足上述所有条件的版本,并且是所有版本中最有效的版本。
注–此处提到的Dekker解决方案仅确保两个进程之间的互斥,如果正确使用数组和变量,可以将其扩展到两个以上的进程。
算法–它需要布尔值数组和整数变量:
var flag: array [0..1] of boolean;
turn: 0..1;
repeat
flag[i] := true;
while flag[j] do
if turn = j then
begin
flag[i] := false;
while turn = j do no-op;
flag[i] := true;
end;
critical section
turn := j;
flag[i] := false;
remainder section
until false;
Dekker解决方案的第一个版本–想法是在进程之间使用公共或共享线程号,并且如果共享线程指示前一个进程已经在运行,则阻止另一个进程进入其关键部分。
Main()
{
int thread_number = 1;
startThreads();
}
Thread1()
{
do {
// entry section
// wait until threadnumber is 1
while (threadnumber == 2)
;
// critical section
// exit section
// give access to the other thread
threadnumber = 2;
// remainder section
} while (completed == false)
}
Thread2()
{
do {
// entry section
// wait until threadnumber is 2
while (threadnumber == 1)
;
// critical section
// exit section
// give access to the other thread
threadnumber = 1;
// remainder section
} while (completed == false)
}
在上述实现中出现的问题是锁步同步,即每个线程在执行时都依赖于另一个。如果其中一个过程完成,则第二个过程将运行,为已完成的过程提供访问权,并等待其轮换,但是,前一个过程已完成,并且永远不会运行以将访问权返回给后一个过程。因此,第二个过程将无限期地等待。
Dekker解决方案的第二版–要删除锁步同步,它使用两个标志来指示其当前状态,并在进入和退出部分进行相应的更新。
Main()
{
// flags to indicate if each thread is in
// its critial section or not.
boolean thread1 = false;
boolean thread2 = false;
startThreads();
}
Thread1()
{
do {
// entry section
// wait until thread2 is in its critical section
while (thread2 == true)
;
// indicate thread1 entering its critical section
thread1 = true;
// critical section
// exit section
// indicate thread1 exiting its critical section
thread1 = false;
// remainder section
} while (completed == false)
}
Thread2()
{
do {
// entry section
// wait until thread1 is in its critical section
while (thread1 == true)
;
// indicate thread2 entering its critical section
thread2 = true;
// critical section
// exit section
// indicate thread2 exiting its critical section
thread2 = false;
// remainder section
} while (completed == false)
}
上述版本中出现的问题是互斥本身。如果在标志更新期间(即在current_thread = true期间)抢占(停止)线程,则一旦抢占线程重新启动,两个线程都进入其临界区,并且当两个标志都为false时,也可以在启动本身上观察到相同的情况。
Dekker解决方案的第三个版本–为了确保相互排斥,它在进入部分本身之前设置了标志。
Main()
{
// flags to indicate if each thread is in
// queue to enter its critical section
boolean thread1wantstoenter = false;
boolean thread2wantstoenter = false;
startThreads();
}
Thread1()
{
do {
thread1wantstoenter = true;
// entry section
// wait until thread2 wants to enter
// its critical section
while (thread2wantstoenter == true)
;
// critical section
// exit section
// indicate thread1 has completed
// its critical section
thread1wantstoenter = false;
// remainder section
} while (completed == false)
}
Thread2()
{
do {
thread2wantstoenter = true;
// entry section
// wait until thread1 wants to enter
// its critical section
while (thread1wantstoenter == true)
;
// critical section
// exit section
// indicate thread2 has completed
// its critical section
thread2wantstoenter = false;
// remainder section
} while (completed == false)
}
此版本的问题是可能出现死锁。两个线程都可以同时将其标志设置为true,并且稍后都将无限期等待。
Dekker解决方案的第四版–使用较小的时间间隔重新检查情况,消除死锁并确保相互排斥。
Main()
{
// flags to indicate if each thread is in
// queue to enter its critical section
boolean thread1wantstoenter = false;
boolean thread2wantstoenter = false;
startThreads();
}
Thread1()
{
do {
thread1wantstoenter = true;
while (thread2wantstoenter == true) {
// gives access to other thread
// wait for random amount of time
thread1wantstoenter = false;
thread1wantstoenter = true;
}
// entry section
// wait until thread2 wants to enter
// its critical section
// critical section
// exit section
// indicate thread1 has completed
// its critical section
thread1wantstoenter = false;
// remainder section
} while (completed == false)
}
Thread2()
{
do {
thread2wantstoenter = true;
while (thread1wantstoenter == true) {
// gives access to other thread
// wait for random amount of time
thread2wantstoenter = false;
thread2wantstoenter = true;
}
// entry section
// wait until thread1 wants to enter
// its critical section
// critical section
// exit section
// indicate thread2 has completed
// its critical section
thread2wantstoenter = false;
// remainder section
} while (completed == false)
}
此版本的问题是无限期推迟。同样,随机时间量是不稳定的,具体取决于实现算法的情况,因此在业务关键型系统中不是可接受的解决方案。
Dekker的算法:最终和完整的解决方案–-想法是使用受欢迎的线程概念来确定进入关键部分的时间。优先线程在提供互斥并避免死锁,无限期延迟或锁步同步的线程之间交替。
Main()
{
// to denote which thread will enter next
int favouredthread = 1;
// flags to indicate if each thread is in
// queue to enter its critical section
boolean thread1wantstoenter = false;
boolean thread2wantstoenter = false;
startThreads();
}
Thread1()
{
do {
thread1wantstoenter = true;
// entry section
// wait until thread2 wants to enter
// its critical section
while (thread2wantstoenter == true) {
// if 2nd thread is more favored
if (favaouredthread == 2) {
// gives access to other thread
thread1wantstoenter = false;
// wait until this thread is favored
while (favouredthread == 2)
;
thread1wantstoenter = true;
}
}
// critical section
// favor the 2nd thread
favouredthread = 2;
// exit section
// indicate thread1 has completed
// its critical section
thread1wantstoenter = false;
// remainder section
} while (completed == false)
}
Thread2()
{
do {
thread2wantstoenter = true;
// entry section
// wait until thread1 wants to enter
// its critical section
while (thread1wantstoenter == true) {
// if 1st thread is more favored
if (favaouredthread == 1) {
// gives access to other thread
thread2wantstoenter = false;
// wait until this thread is favored
while (favouredthread == 1)
;
thread2wantstoenter = true;
}
}
// critical section
// favour the 1st thread
favouredthread = 1;
// exit section
// indicate thread2 has completed
// its critical section
thread2wantstoenter = false;
// remainder section
} while (completed == false)
}
此版本保证了对关键解决方案问题的完整解决方案。
参考 –
德克算法-csisdmz.ul.ie
德克算法-维基百科