linux下的同步與互斥

來源:互聯網
上載者:User

標籤:

linux下的同步與互斥

  談到linux的並發,必然涉及到線程之間的同步和互斥,linux主要為我們提供了幾種實現線程間同步互斥的 

機制,本文主要介紹互斥鎖,條件變數和訊號量。互斥鎖和條件變數包含在pthread線程庫中,使用時需要包含 

<pthread.h>標頭檔。而使用訊號量時需要包含<semaphore.h>標頭檔。 

1.互斥鎖 

    型別宣告:pthread_mutex_t mutex; 

    對互斥量的初始化: 

        程式在使用pthread_mutex_t之前需要先對其進行初始化,對於靜態分配的pthread_mutex_t變數來說, 

        只要將PTHREAD_MUTEX_INITIALIZER賦給變數就行了,語句如下: 

            static pthread_mutex_t mutex=PTHREAD_mutex_INITIALIZER; 

        而對於動態分配或沒有預設互斥屬性的互斥變數來說,要調用pthread_mutex_init函數來執行初始化工 

        作。函式宣告如下: 

            int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t* attr); 

        mutex是指向一個互斥量的指標,attr是指向一個屬性結構體的指標,為NULL時使用預設屬性。 

        需要注意的是pthread_mutex_init函數只能恰好執行一次,重複執行的結果是未定義的。 

    對互斥量的操作: 

        int pthread_mutex_lock(pthread_mutex_t* mutex);//對互斥量執行鎖定操作 

        int pthread_mutex_unlock(pthread_mutex_t* mutex);//對互斥量執行解鎖操作 

    對互斥量的銷毀: 

        int pthread_mutex_destroy(pthread_mutex_t* mutex);// 

    使用方法: 

        以下代碼用互斥量來保護一個臨界區: 

        pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//初始化 

        pthread_mutex_lock(&mutex);//獲得鎖 

        /*critical section code*/ 

        pthread_mutex_unlock(&mutex);//釋放鎖 

    通常比較適用的方法是將編寫一組訪問臨界區的函數,將鎖定調用都放在這些函數中,這是確保對對象的拍他 

    性訪問的一種方法,這樣鎖定機制對調用線程就是透明的了。 

     

2.條件變數 

    有時,我們可能需要讓線程在某個條件滿足之前一直等待,在未使用條件變數之前,您可能會使用忙等待,如 

    下列代碼: 

        while(x!=y); 

    這樣的方式,然而這種佔著茅坑不拉屎的行為是非常不被提倡的。因此,我們引入條件變數的概念來是線程在 

    某個條件不滿足是進入掛起狀態。 

    型別宣告:pthread_cond_t cond; 

    對條件變數的初始化: 

        程式在使用pthread_cond_t變數之前必須對其進行初始化。對於靜態分配的pthread_cond_t變數來說, 

        只要將PTHREAD_COND_INITIALIZER賦給變數就星了,語句如下: 

        pthread_cond_t cond=PTHREAD_COND_INITIALIZER; 

    對於動態分配的或沒有預設屬性的變數來說,就要調用pthread_cond_init函數來執行初始化。函式宣告如下: 

        int pthread_cond_init(pthread_cond_t* cond,const pthread_cond_attr_t* attr); 

        cond是指向一個條件變數的指標,attr是指向一個屬性結構體的指標,為NULL時使用預設屬性。 

    對條件變數的操作: 

        int pthread_cond_wait(pthread_cond_* cond,pthread_mutex_t* mutex);//使線程阻塞於某個條件。 

        int pthread_cond_signal(pthread_cond_t* cond);//喚醒某個阻塞在cond上的線程。 

    對條件變數的銷毀: 

        int pthread_cond_destroy(pthread_cond_t* cond); 

    使用方法: 

        條件變數是與斷言或條件的測試一同調用的,以此來實現將條件變數關聯到某個斷言上去。通常線程會對 

        一個條件進行測試,如果失敗,就會調用pthread_cond_wait函數將線程阻塞。範例程式碼如下: 

            pthread_mutex_lock(&mutex); 

            while( a<b ) 

                pthread_cond_wait(&cond,&mutex); 

            pthread_mutex_unlock(&mutex); 

        調用線程應該在它測試或調用pthread_cond_wait之前獲得一個互斥量,以避免在測試條件的時候有其他 

        線程改寫條件中變數的值。pthread_cond_wait函數中第二個參數是一個互斥量類型的指標,線程在調用 

        pthread_cond_wait後會隱式的原子地釋放mutex互斥量並阻塞,允許其他線程獲得互斥量並修改斷言中 

        的變數。當線程成功的從pthread_cond_wait中返回時,它就再次擁有了互斥量,並且不用顯式的重新獲 

        得互斥量。 

        當其他線程修改了斷言中變數的值後可以調用pthread_cond_signal函數來喚醒一個等待在某個斷言成真 

        的線程。也可以使用pthread_cond_broadcast(pthread_cond_t*)函數來喚醒所有等待在某個條件變數 

        上的線程。在修改斷言中出現的任一變數之前要獲得互斥量。範例程式碼如下: 

            pthread_mutex_lock(&mutex); 

            a++; 

            pthread_cond_signal(&cond);//pthread_cond_broadcast(&cond); 

            pthread_mutex_unlock(&mutex); 

             

3.訊號量 

    訊號量是一個整型變數,它帶有兩個原子操作wait和signal。wait操作還可以被稱為down、P操作。signal操 

    作還可以被稱為up、V、post操作。 

    如果S大於0,wait操作就在一個原子操作中對其進行減量運算。如果S等於0,wait操作就就在一個原子操作中 

    測試S,阻塞調用程式,將調用程式放入wait的等待隊列中。 

    如果有線程在訊號量上阻塞,則S必然等於0,signal操作就會解除對某一個等待線程的阻塞。如果S大於0,即 

    沒有線程阻塞在訊號量上,signal就對S進行增量操作。 

    可以把訊號量理解為臨界區中資源的可用數量,wait表示對資源的申請,當沒有可用資源時訊號量為0,signal 

    表示線程使用資源後,對資源的釋放。 

    下面介紹幾種通過訊號量來控制線程按某種順序執行的方法: 

    1.線程1中a先於線程2中b執行[S初始話為0] 

        Process 1: 

            a; 

            signal(&S); 

        Process 2: 

            wait(&S); 

            b; 

    2.線程1中a於線程2中b語句交替執行[S,Q初始化為1] 

        Process 1: 

            while(1){ 

                wait(&S); 

                a; 

                signal(&Q); 

            } 

        Process 2: 

            while(1){ 

                wait(&Q); 

                b; 

                signal(&S); 

            } 

    可通過讓S為0Q為1,或讓S為1Q為0,來保證讓a或b先執行。 

    需要注意的是,為了避免申請多個資源發生死結,應按照相同的順序申請資源,這裡公司面試的時候經常會被 

    問到。 

     

     

    linux中訊號量有無名訊號量和命名訊號量之分,無名訊號量可用於線程之間的同步和互斥,命名訊號量可用 

    於進程間的通訊,命名訊號量與具名管道相似,以檔案的形式儲存於磁碟上。 

     

  無名訊號量: 

    型別宣告: 

        sem_t sem; 

    初始化: 

        int sem_init(sem_t* sem,int pshared,int value); 

        參數pshared為0,表示訊號量只能由初始化這個訊號量的進程中的線程使用。 

        value表示要將sem初始化的值。value不能為負。 

    操作: 

        int sem_post(sem_t* sem);//signal操作 

        int sem_wait(sem_t* sem);//wait操作 

    銷毀: 

        int sem_destroy(sem_t* sem); 

    使用方法: 

        通常先由主線程調用sem_init對訊號量進行初始化。然後在其他線程中調用post或wait函數。範例程式碼 

   

  • 本文來自:Linux教程網

linux下的同步與互斥

聯繫我們

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