Unix/linux進程及線程間同步技術總結【學習總結,請勿吐槽。。。】

來源:互聯網
上載者:User

  為允許線上程或進程間共用資料,同步通常是必須的。常見的同步方式有:互斥鎖、條件變數、讀寫鎖、訊號量。另外,對於進程間的同步,也可以通過處理序間通訊的方式進行同步,包括管道(無名管道、有名管道)、訊號量、訊息佇列、共用記憶體、遠端程序呼叫,當然也可以通過Socket來進行網路控制。

一.  互斥鎖和條件變數是同步的基本組成部分

  互斥鎖和條件變數出自Posix.1線程標準,多用來同步一個進程中各個線程。但如果將二者存放在多個進程間共用的記憶體區中,它們也可以用來進行進程間的同步。

1. 互斥鎖用於保護臨界區,以保護任何時刻只有一個線程在執行其中的代碼,其大體輪廓大體如下:

  lock_the_mutex(...);

  臨界區

  unlock_the_mutex(...);

  下列三個函數給一個互斥鎖上鎖和解鎖:

  #include <pthread.h>

  int pthread_mutex_lock(pthread_mutex_t *mptr);  //若不能立刻獲得鎖,將阻塞在此處

  int pthread_mutex_trylock(pthread_mutex_t *mptr);  //若不能立刻獲得鎖,將返回EBUSY,使用者可以根據此傳回值做其他動作,非阻塞模式

  int pthread_mutex_unlock(pthread_mutex_t *mptr);  //釋放鎖

  互斥鎖通常用於保護由多個線程或多個進程分享的共用資料(Share Data)

2.  條件變數,它是發送訊號與等待訊號。互斥鎖使用者上鎖,條件變數則用於等待。一般來說,在一個進程/線程中調用pthread_cond_wait(..)等待某個條件的成立,此時該進程阻塞在這裡,另外一個進程/線程進行某種操作,當某種條件成立時,調用pthread_cond_signal(...)來發送訊號,從而使pthread_cond_wait(...)返回。此處要注意的是,這裡所談到的訊號,不是系統層級的SIGXXXX訊號,只是用訊號這個詞語更容易理解。條件變數與訊號量更接近或者就可以認為是訊號量。

  下列兩個函數用來對條件變數進行控制:

  #include <pthread.h>

  int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);

  int pthread_cond_signal(pthread_cond_t *cptr);

  由代碼我們可以看出,條件變數的使用是需要結合鎖機制的,即上面所提到的互斥鎖。也就是說,一個進程/線程要等到臨界區的共用資料達到某種狀態時再進行某種操作,而這個狀態的成立,則是由另外一個進程/線程來完成後發送訊號來通知的。

  其實想一想,pthread_cond_wait函數也可以用一個while死迴圈來等待條件的成立,但要注意的是,使用while死迴圈會嚴重消耗CPU,而pthread_cond_wait則是採用線程睡眠的方式,它是一種等待模式,而不是一直的檢查模式。

  總的來說,給條件變數發送訊號的代碼大體如下:

  pthread_mutex_lock(&mutex);

  設定條件為真

  pthread_cond_signal(&cond);  //發送訊號

  pthread_mutex_unlock(&mutex);  

  等待條件並進入睡眠以等待條件變為真的代碼大體如下:

  pthread_mutex_lock(&mutex); 

  while(條件為假)

    pthread_cond_wait(&cond,&mutex);  

  執行某種操作

  pthread_mutex_unlock(&mutex);

  在這裡需要注意的是,pthread_cond_wait(&cond,&mutex)是一個院子操作,當它執行時,首先對mutex解鎖,這樣另外的線程才能得到鎖來修改條件,pthread_cond_wait解鎖後,再將本身的線程/進程投入睡眠,另外,當該函數返回時,會再對mutex進行加鎖,這樣才能“執行某種操作”後unlock鎖。


二、 讀寫鎖

  顧名思義,讀寫鎖也是一種鎖,他是在互斥鎖的基礎上進行了改進,當一個進程/線程獲得寫入鎖時,其他的進程/線程仍然可以獲得鎖,只不過獲得的是讀取鎖,因為一個進程/線程寫入,不影響其他進程/線程的讀操作。

 

三、 訊號量

  英文:semaphore,它是一種專門用於提供不同進程間或線程間同步手段的原語。可以通過來理解它。

        進程A                               進程B

          \          /

     進程    \         /

        ----------------------------------------------------

     核心     \      /

              訊號量

  也就是說,訊號量是由核心來維護的,他獨立出進程。因此可以通過它來進行同步。

  一般來說,是基於Posix有名訊號量,可以認為它是系統中的一個特殊檔案(因為在Linux中,一切都可以認為是檔案),因為在進程間的通訊、同步中用的比較多,如果是線程之間的同步,經常用基於Posix記憶體的訊號量。(基於記憶體的訊號量必須在建立時指定是否在進程間共用,有名訊號量隨核心有持久性,需手工刪除,而基於記憶體的訊號量具有隨進程的持久性)

  對於訊號量的工作原理,其實和互斥鎖+條件變數相似。

  主要函數有:sem_open、sem_close、sem_unlink,這裡要注意,close只是關閉訊號量,但並未從系統中刪除,而unlink是刪除該訊號量。

  sem_wait和sem_trywait函數,他們和pthread_cond_wait功能相似,都是等待某個條件的成立,sem_wait和sem_trywait的區別是,當所指定的訊號量的值為0時,後者並不將調用者投入睡眠,而是立刻返回EAGAIN,即重試。

  sem_post和sem_getvalue函數,sem_post將指定的訊號量加一,然後喚醒正在等待該訊號量值變為正數的任意線程。sem_getvalue是用來擷取當前訊號量值的函數。

 

總結:

  互斥鎖、條件變數、訊號量三者的差別:

  (1) 互斥鎖必須總是由給他上鎖的線程解鎖(因為此時其他線程根本得不到此鎖),訊號量沒有這種限制:一個線程等待某個訊號量,而另一個線程可以掛出該訊號量

  (2)每個訊號量有一個與之關聯的值,掛出時+1,等待時-1,那麼任何線程都可以掛出一個訊號,即使沒有線程在等待該訊號量的值。不過對於條件變數來說,如果pthread_cond_signal之後沒有任何線程阻塞在pthread_cond_wait上,那麼此條件變數上的訊號丟失。

  (3)在各種各樣的同步技巧中,能夠從訊號處理常式中安全調用的唯一函數是sem_post

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.