進來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函數中賦初值,也是可行的。
如有錯誤,請指正,感激不盡!
參考書籍:
《Modern.Operating.Systems.3rd.Edition》作者:Andrew S.Tanenbaum
參考網站:
https://zh.wikipedia.org/wiki/Peterson
(貌似要翻牆)
http://baike.baidu.com/link?url=h-hOJrsTo24PXgPweosxSpnzeaKhJwhz7N3PbZhG_2_M_8U6RQqEYt9KWGzyclw6lr9Qbi4FkLdyrIKDeBQ6qq