1. 程式人生 > >Peterson演算法的簡單分析

Peterson演算法的簡單分析

最近作業系統學到程序同步,介紹了Peterson演算法。

第一種(謙讓式)

上課教材《作業系統概念》第七版(翻譯版)和百度百科,還有查到的絕大部分的資料中,都是下面這種方法實現的。
下面程式碼是教材中摘的(P169)。

/*程序Pi的結構*/
do{
	flag[i] = TRUE;
	turn = j;
	while(flag[j] && turn == j);
	//臨界區
	flag[i] = FALSE;
	//剩餘區
} while(TRUE);

為什麼說這種演算法是一種“謙讓”的演算法呢?因為當程序i將flag[i]設定為TRUE之後,又把turn設定為j。
flag[i]=TRUE表示:程序i想進入臨界區。
而turn = j表示:現在輪到程序j進入臨界區了。

所以程序i的進入區程式碼是這樣的

flag[i] = TRUE;
turn = j;
while(flag[j] == TRUE && turn == j);

程序j的進入區程式碼是這樣的:

flag[j] = TRUE;
turn = i;
while(flag[i] == TRUE && turn == i);

分析:
首先,如果是程序i第一次開始執行,那它可以順利進入臨界區,因為flag[j]=FALSE,程序j還不想進入臨界區!
其次,如果程序i和程序j已經在併發執行了,它們的排程順序是未知的,假設每個程序每次執行一行程式碼,交替執行。那先執行的程序就“賺了”,比如程序i先執行,那麼它會先將turn“謙讓”地設定為j,但接下來輪到程序j執行了,它也“謙讓”地將turn設定為i。這時又輪到了程序i執行了,而且我們可以發現,while中第二個條件已經不滿足了!這時程序i就進入了臨界區!然後我們把情況一般化,不再假設每個程序交替地執行一行程式碼,只要一個程序後執行了turn = i;(或turn = j;)這條語句,那麼另一個程序就可以進入臨界區。(分析的時候重點關注一點:另一個程序到底想不想進入臨界區?)

第二種

只在《現代作業系統》第三版中找到了這種方法。下面程式碼是書上摘的(P69)。
沒找到第四版的書和資源,有可能第四版也改成第一種實現方法了。所以我很奇怪是不是利用flag和turn實現的加鎖都叫Peterson演算法?

#define FALSE 0
#define TRUE  1
#define N     2                                           /* 程序數量 */
  
int turn;                                                 /* 現在輪到誰?*/
int interested[N];                                        /* 所有值初始化為0(FALSE)*/

void enter_region(int process)                            /* 程序是0或1 */
{
	int other;                                            /* 其他程序號 */

	other = 1 - process;                                  /* 另一方程序 */
	interested[process] = TRUE;                           /* 表名所感興趣的 */
	turn = process;                                       /* 設定標誌 */
	while(turn == process && interested[other] ==TRUE);   /* 空語句 */
}

void leave_region(int process)                            /* 程序:誰離開?*/
{
	interested[process] = FALSE;                          /* 表示離開臨界區 */
}

分析:
這種演算法本質上和第一種的區別就在於進入區
(變數命名不同
process表示當前程序自身,other表示另一個程序
interested表示flag)

interested[process] = TRUE;
turn  = process;
while(turn == process && interested[other] == TRUE);

可以看到這種方法不再謙讓了,程序自己想進入臨界區,於是把turn設定成自己。

所以兩個程序都把turn設定為自己的程序號,但只有後被儲存進去的程序號才有效,前一個寫進去的因為被重寫而丟失。

分析:
首先,還是假設程序i第一次開始執行,那它可以順利進入臨界區,因為interested[j]=FALSE,程序j還不想進入臨界區!
其次,交替執行的過程中,假設某一時刻程序i正處於臨界區,那麼interested[i] = TRUE 且 turn = i,那麼這時如果程序j也想進臨界區,它會先把interested[j]改為TRUE,然後把turn改為j。但它會在while迴圈那裡忙等待,直到程序i退出了臨界區,把interested[i]改為FALSE。

總結

無論是否“謙讓”,都實現了程序互斥,並滿足了這三點:

  1. 同一時刻只有一個程序能進入臨界區
  2. 前進:不在臨界區的程序不能阻止另一個程序進入臨界區
  3. 有限等待:不得使程序無限期等待進入臨界區