📜  流程同步中的Dekker算法

📅  最后修改于: 2021-05-04 19:52:06             🧑  作者: Mango

先决条件–流程同步,进程间通信
为了获得这种互斥,有界等待和进展,已经实现了几种算法,其中之一是Dekker算法。要了解该算法,让我们首先了解关键部分问题的解决方案。
一个过程通常表示为:

do {
    //entry section
        critical section
    //exit section
        remainder section
} while (TRUE);

关键截面问题的解决方案必须确保满足以下三个条件:

  1. 互斥
  2. 进步
  3. 有限的等待

确保上述所有因素的解决方案之一是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
德克算法-维基百科