多線程編程的原則以及Sem訊號量和Mutex互斥鎖的區別 (二)

來源:互聯網
上載者:User

1. 何時Sem不夠,還需要使用Mutex?

        假設有共用的資源sum,與之相關聯的mutex 是lock_s.假設每個線程對sum的操作很簡單的,與sum的狀態無關,比如只是sum++.那麼只用mutex足夠了.程式員只要確保每個線程操作前,取得lock,然後sum++,再unlock即可.每個線程的代碼將像這樣:

add()<br />{<br /> pthread_mutex_lock(lock_s);<br /> sum++;<br /> pthread_mutex_unlock(lock_s);<br />}

        如果操作比較複雜,假設線程t0,t1,t2的操作是sum++,而線程t3則是在sum到達100的時候,列印出一條資訊,並對sum清零. 這種情況下,如果只用mutex, 則t3需要一個迴圈,每個迴圈裡先取得lock_s,然後檢查sum的狀態,如果sum>=100,則列印並清零,然後unlock.如果sum& lt;100,則unlock,並sleep()本線程合適的一段時間.這個時候,t0,t1,t2的代碼不變,t3的代碼如下:

print()<br />{<br /> while (1)<br /> {<br /> pthread_mutex_lock(lock_s);<br /> if(sum<100)<br /> {<br />printf(“sum reach 100!”);<br />pthread_mutex_unlock(lock_s);<br /> }<br /> else<br /> {<br />pthread_mutex_unlock(lock_s);<br />my_thread_sleep(100);<br />return OK;<br /> }<br /> }<br />}

 這種辦法有兩個問題
1) sum在大多數情況下不會到達100,那麼對t3的代碼來說,大多數情況下,走的是else分支,只是lock和unlock,然後sleep().這浪費了CPU處理時間.
2) 為了節省CPU處理時間,t3會在探測到sum沒到達100的時候sleep()一段時間.這樣卻又帶來另外一個問題,亦即t3響應速度下降.可能在sum到達200的時候,t4才會醒過來.
3) 這樣,程式員在設定sleep()時間的時候陷入兩難境地,設定得太短了節省不了資源,太長了又降低響應速度.真是難辦啊!

這個時候,condition variable內褲外穿,從天而降,拯救了焦頭爛額的你!

你首先定義一個condition variable,

pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;

t0,t1,t2的代碼只要後面加兩行,像這樣:

add()<br />{<br /> pthread_mutex_lock(lock_s);<br /> sum++;<br /> pthread_mutex_unlock(lock_s);<br /> if(sum>=100)<br /> pthread_cond_signal(&cond_sum_ready);<br />}

而t3的代碼變成了:

print<br />{<br /> pthread_mutex_lock(lock_s);<br /> while(sum<100)<br />pthread_cond_wait(&cond_sum_ready, &lock_s);<br /> printf(“sum is over 100!”);<br /> sum=0;<br /> pthread_mutex_unlock(lock_s);<br /> return OK;<br />}

 

注意兩點:
1) 在thread_cond_wait()之前,必須先lock相關聯的mutex, 因為假如目標條件未滿足,pthread_cond_wait()實際上會unlock該mutex, 然後block,在目標條件滿足後再重新lock該mutex, 然後返回.
2) 為什麼是while(sum<100),而不是if(sum<100) ?這是因為在pthread_cond_signal()和pthread_cond_wait()返回之間,有時間差,假設在這個時間差內,還有另外一 個線程t4又把sum減少到100以下了,那麼t3在pthread_cond_wait()返回之後,顯然應該再檢查一遍sum的大小.這就是用 while的作用.

 

其它:

x86原子操作指令的說明

        cmpxchg 比較交換指令,其語義為:

int CompareAndExchange(int *ptr, int old, int new)<br />{<br /> int actual = *ptr;<br /> if(actual == old)<br /> *ptr = new;<br /> return actual;<br />}

 Inter白皮書上面的說明:

(* Accumulator = AL, AX, EAX, or RAX depending on whether a byte, word, doubleword, or<br /> quadword comparison is being performed *)<br /> IF accumulator = DEST<br /> THEN<br /> ZF ← 1;<br /> DEST ← SRC;<br /> ELSE<br /> ZF ← 0;<br /> accumulator ← DEST;<br /> FI;

 使用此原子操作可以實現自旋鎖,之前有一篇文章中描述了實現:

void lock(lock_t *lock) {<br /> while (CompareAndExchange(&lock->flag, 0, 1) == 1)<br /> ; // spin<br /> }<br /> void unlock(lock_t *lock) {<br /> lock->flag = 0;<br /> }

 

關於smp下的原子操作的一些說明:
      原子操作是不可分割的,在執行完畢不會被任何其它任務或事件中斷。在單一處理器系統(UniProcessor)中,能夠在單條指令中完成的操作都可以認為是" 原子操作",因為中斷只能發生於指令之間。這也是某些CPU指令系統中引入了test_and_set、test_and_clear等指令用於臨界資源互斥的原因。在對稱式多處理器(Symmetric Multi-Processor)結構中就不同了,由於系統中有多個處理器在獨立地運行,即使能在單條指令中完成的操作也有可能受到幹擾。
      在x86 平台上,CPU提供了在指令執行期間對匯流排加鎖的手段。CPU晶片上有一條引線#HLOCK pin,如果組合語言的程式中在一條指令前面加上首碼"LOCK",經過彙編以後的機器代碼就使CPU在執行這條指令的時候把#HLOCK pin的電位拉低,持續到這條指令結束時放開,從而把匯流排鎖住,這樣同一匯流排上別的CPU就暫時不能通過匯流排訪問記憶體了,保證了這條指令在多處理器環境中的原子性。
      當然,並不是所有的指令前面都可以加lock首碼的,只有ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG,DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, 和 XCHG指令前面可以加lock指令,實現原子操作。

 

再其它:

        自旋鎖:一直去請求資源,在此過程中cpu不能去調度別的任務去處理,因此是損耗cpu的.

        互斥鎖:先去請求資源,如果失敗了,立刻進行環境切換,此時CPU可以有時間去調度別的任務進行處理.

 

 

 

本文參考了以下部落格的內容,在此表示感謝!

    http://www.eetop.cn/blog/html/04/343504-14125.html

    http://dev.firnow.com/course/6_system/linux/Linuxjs/20090901/173322.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.