Peterson算法

進來Bear正在學習鞏固並行的基礎知識,所以寫下這篇基礎的有關並行算法的文章。

在講述兩個算法之前,需要明確一些概念性的問題,

Race Condition(競爭條件),Situations  like  this,  where  two  or  more processes  are  reading or writing some shared data and the final result depends on who runs precisely when, are called race conditions.多個進程(線程)讀寫共享區域(共享文件、共享變量、共享內存等)時,最後的結果依賴於他們執行的相對時間。

Critical Regions(關鍵區域),That part of the program where the shared memory is accessed.在程序中,訪問共享內存的部分。

Mutual exclusion(互斥), that is, some way of making sure that if one process is using a shared  variable or file, the other processes will be excluded from doing the same thing.指在一個進程在使用共享區域時,防止另外的進程做同樣的事情。

同樣,需要四個條件來找到一個好的解決方案,實現進程(線程)之間的互斥:

Dekker算法與Peterson算法就是用來實現進程或者線程之間的互斥。

Dekker算法:(參考了百度百科上面的Dekker算法解析,還是挺易懂的)

Dekker算法可以用於控制兩個進程(線程)之間的同步,如下實現的功能就是專門用於線程的同步:

其中,flag[2]用來表示是否想要使用關鍵區,turn用來表示具有訪問權限的進程ID。(重點看註釋,通過註釋,挺好理解的喲~

複製代碼
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define true 1
#define false 0
typedef int bool;
bool flag[2];
int turn;
void visit(int num)
{
        sleep(1);
        printf("P%d is visting\n",num);
}
void P0()
{
        while(true)
        {
                flag[0] = true;//P0想使用關鍵區。
                while(flag[1])//檢查P1是不是也想用?
                {
                        if(turn == 1)//如果P1想用,則查看P1是否具有訪問權限?
                        {
                                flag[0] = false;//如果有,則P0放棄。
                                while(turn == 1);//檢查turn是否屬於P1。
                                flag[0] = true;//P0想使用。
                        }
                }
                visit(0); //訪問Critical Partition。
                turn = 1; //訪問完成,將權限給P1。
                flag[0] = false;//P0結束使用。
        }
}
void P1()
{
        while(true)
        {
                flag[1] = true; //P1想使用關鍵區。
                while(flag[0]) //檢查P0是不是也想用?
                {
                        if(turn == 0) //如果P0想用,則查看P0是否具有訪問權限?
                        {
                                flag[1] = false; //如果有,則P1放棄。
                                while(turn == 0); //檢查turn是否屬於P1。
                                flag[1] = true; // P1想使用。
                        }

                }
                  visit(1); //訪問Critical Partition。
                turn = 0; //訪問完成,將權限給P0。
                flag[1] = false; //P1結束使用。
        }
}

void main()
{
        pthread_t t1,t2;
        flag[0] = flag[1] = false;
        turn = 0;
        int err;
        err =  pthread_create(&t1,NULL,(void*)P0,NULL);
        if(err != 0) exit(-1);
        err = pthread_create(&t2,NULL,(void*)P1,NULL);
        if(err != 0 ) exit(-1);
        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        exit(0);
}
複製代碼

如上所示,如果flag數組和turn都沒有符合使用關鍵區的條件的時候,是不可能進入關鍵區的。

Peterson算法:

Peterson算法也是保證兩個進程(線程)實現互斥的方法,比之前的Dekker算法更加簡單,他同樣提供了兩個變量,保證進程不進入關鍵區,一個是flag[2],一個是turn,兩者的表達意思也類似,flag數組表示能否有權限使用關鍵區,turn是指有訪問權限的進線程ID。(註釋很重要,幫助你理解

複製代碼
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define true 1
#define false 0
typedef int bool;
bool flag[2];
int turn;
void procedure0()
{
        while(true)
        {
                flag[0] = true;
                turn = 1;
                while(flag[1] && turn == 1)//退出while循環的條件就是,要麼另一個線程
//不想要使用關鍵區,要麼此線程擁有訪問權限。
                {
                        sleep(1);
                        printf("procedure0 is waiting!\n");
                }
                //critical section
                flag[0] = false;
        }
}
void procedure1()
{
        while(true)
        {
                flag[1] = true;
                turn = 0;
                while(flag[0] && turn == 0)
                {
                        sleep(1);
                        printf("procedure1 is waiting!\n");
                }
                //critical section
                flag[1] = false;
        }
}
void main()
{

        pthread_t t1,t2;
        flag[0] = flag[1] = false;
        int err;
        turn = 0;
        err =  pthread_create(&t1,NULL,(void*)procedure0,NULL);
        if(err != 0) exit(-1);
        err = pthread_create(&t2,NULL,(void*)procedure1,NULL);
        if(err != 0 ) exit(-1);
        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        exit(0);
}
複製代碼

Bear將turn的賦值放在while循環的後面,然後main函數中賦初值,也是可行的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章