一. 原子操作的定義 原子操作,是指一組相關聯的操作要麼都不間斷的執行,要麼都不執行。 二. 原子操作對同步與互斥的意義 1. 討論原子操作的意義之前,先瞭解操作系統中如下概念: 競爭條件:兩個或多個進程或線程讀寫某些共用數據,而最後的結果取決於進程運行的精確時序,稱為競爭條件。 臨界區:把對共用內 ...
一. 原子操作的定義
原子操作,是指一組相關聯的操作要麼都不間斷的執行,要麼都不執行。
二. 原子操作對同步與互斥的意義
1. 討論原子操作的意義之前,先瞭解操作系統中如下概念:
競爭條件:兩個或多個進程或線程讀寫某些共用數據,而最後的結果取決於進程運行的精確時序,稱為競爭條件。
臨界區:把對共用記憶體進行訪問的程式片段稱作臨界區。
2. 競爭問題舉例
考慮兩個線程列印數字10~1,線程總是在列印counter當前值後對其執行減一操作,代碼如下。
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <pthread.h> 4 5 int counter=10; 6 7 void *myThread(); 8 9 int main(void) 10 { 11 void *ret1,*ret2; 12 pthread_t t1,t2; 13 pthread_create(&t1,NULL,&myThread,NULL); 14 pthread_create(&t2,NULL,&myThread,NULL); 15 pthread_join(t1,&ret1); 16 pthread_join(t2,&ret2); 17 return 0; 18 } 19 20 void *myThread() 21 { 22 while(counter>0){ 23 printf("%d\n",counter); 24 counter--; 25 } 26 27 pthread_exit("Finished\n"); 28 }View Code
若是單線程的情況下,這種列印方式不會有任何問題。然而兩個線程的執行結果如下圖所示,多輸出一個數字10。這種情況是由於一個線程判斷並輸出變數counter之後,執行counter減一操作之前,另一個線程也開始判斷並輸出變數counter,這個時候counter的值還未來的及發生改變,因此便輸出來了兩個數字10。
這種問題的造成是由於變數counter讀與寫操作的不連續性(非原子性)造成的,根據鄰接區的定義,我們將這組對counter讀與寫的代碼成為臨界區。解決這種臨界區的競爭問題的可行方案是將鄰接區程式片段改造成原子操作,比如,可以使用互斥鎖改造臨界區為(偽)原子操作。之所以稱之為偽原子操作,是因為一個進程或線程進入鄰接區期間,其它進程與線程仍然可能獲取CPU執行時間,但互斥鎖操作的原子性足可以保證同一時間只能有一個進程或線程進入臨界區執行。
使用互斥鎖的代碼以及運行結果。
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <pthread.h> 4 #include <semaphore.h> 5 6 int counter=10; 7 pthread_mutex_t mutex; 8 9 void *myThread(); 10 11 int main(void) 12 { 13 void *ret1,*ret2; 14 pthread_t t1,t2; 15 16 pthread_mutex_init(&mutex,NULL); 17 18 pthread_create(&t1,NULL,&myThread,NULL); 19 pthread_create(&t2,NULL,&myThread,NULL); 20 pthread_join(t1,&ret1); 21 pthread_join(t2,&ret2); 22 23 pthread_mutex_destroy(&mutex); 24 25 return 0; 26 } 27 28 void *myThread() 29 { 30 31 while(1){ 32 pthread_mutex_lock(&mutex);//上鎖 33 if(counter>0){ 34 printf("%d\n",counter); 35 counter--; 36 } 37 if(counter==0){ 38 pthread_mutex_unlock(&mutex);//開鎖 39 break; 40 } 41 pthread_mutex_unlock(&mutex);//開鎖 42 } 43 44 pthread_exit("Finished\n"); 45 }View Code
3. 原子操作的意義
從上面的例子可以看出,原子操作的原子性對於解決同步問題和避免競爭條件是絕對必要的。
三. 原子操作實現的硬體支持
互斥與同步問題可以使用諸如互斥鎖與信號量之類的方案解決,那麼互斥鎖與信號量本身操作的原子性又是如何保證的呢?
1. 原子指令
某些電腦中,特別是哪些設計為多處理器的電腦,支持類似TSL、XCHG的指令。XCHG的功能:交換指令XCHG是兩個寄存器,寄存器和記憶體變數之間內容的交換指令,兩個操作數的數據類型要相同,可以是一個位元組,也可以四一個字,也可以是雙字。XCHG指令是對數據進行讀寫操作的原子指令,讀寫完成前無法中斷,TSL指令類似。通過諸如XCHG這類可同時對數據進行讀寫操作的原子指令,可在軟體層面實現更多的原子操作。註意:XCHG無法處理多CPU下的同步與互斥問題,多個CPU可以同時執行XCHG指令讀取相同的數據。執行TSL指令的CPU將鎖住記憶體匯流排,以禁止其它CPU在本指令結束之前訪問記憶體,可以處理多CPU情形下的同步與互斥問題。
2. 中斷屏蔽
中斷屏蔽可以保證CPU執行一段指令(開、關中斷指令間的所有指令)結束前不會被打斷,保證了原子性。應該註意到將中斷屏蔽的許可權交給用戶程式將會是非常可怕的,時鐘中斷被屏蔽可讓用戶程式永遠占有CPU。同時,多CPU的情形下,中斷屏蔽無法保證其它CPU不訪問記憶體。因此,中斷屏蔽僅適合單CPU情形下的內核代碼解決互斥與同步問題。