1. 程式人生 > >執行緒同步方法:

執行緒同步方法:

  1.  互斥鎖
     

      lock_the_mutex(...);

  臨界區

  unlock_the_mutex(...);

 

互斥鎖通常用於保護由多個執行緒或多個程序共享的共享資料(Share Data)

 

互斥鎖是用在多執行緒多工互斥的,一個執行緒佔用了某一個資源,那麼別的執行緒就無法訪問,直到這個執行緒unlock,其他的執行緒才開始可以利用這 個資源。比如對全域性變數的訪問,有時要加鎖,操作完了,再解鎖。

 

A執行緒的臨界區中的邏輯一次性執行完再解鎖,其它執行緒在A執行緒解鎖前沒有辦法拿到鎖,無法執行。目的是防止出現A執行緒中臨界區中的邏輯執行到一半的時候,其它執行緒打斷A執行緒執行,之後再執行剩餘的部分(其它執行緒不能拿到鎖,所以阻塞)。

 

#include <pthread.h> 

 

static  pthread_mutex_t  alock;  //定義鎖

 

pthread_mutex_init(&alock, (const pthread_mutexattr_t *) NULL);    //初始化鎖

 

pthread_mutex_lock(&alock);   //加鎖, 若不能立刻獲得鎖, 將阻塞在這裡。

……..

pthread_mutex_unlock(&alock);  

//解鎖

 

2.   條件變數

 

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

  一個程序/執行緒要等到臨界區的共享資料達到某種狀態時再進行某種操作,而這個狀態的成立,則是由另外一個程序/執行緒來完成後傳送訊號來通知的。

其實想一想,pthread_cond_wait函式也可以用一個while死迴圈來等待條件的成立,但要注意的是,使用while死迴圈會嚴重消耗CPU,而

pthread_cond_wait則是採用執行緒睡眠的方式,它是一種等待模式,而不是一直的檢查模式。

  總的來說,給條件變數傳送訊號的程式碼大體如下:

  pthread_mutex_lock(&mutex);

  設定條件為真

  pthread_mutex_unlock(&mutex);  

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

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

  pthread_mutex_lock(&mutex); 

  while(條件為假)

   pthread_cond_wait(&cond,&mutex);  //等待訊號, wait必須放在lockunlock之間

  執行某種操作

  pthread_mutex_unlock(&mutex);

  在這裡需要注意的是,pthread_cond_wait(&cond,&mutex)是一個原子操作,當它執行時,首先對mutex解鎖,這樣另外的執行緒才能得到鎖來修改條件,pthread_cond_wait執行時會有一個先解鎖的動作,執行完最後加鎖。

 

使用舉例:

 

#include <pthread.h>

 

static pthread_mutex_t alock;   //定義互斥鎖

static pthread_cond_t  acond;  //定義訊號量

 

 

pthread_mutex_init(&alock, (const pthread_mutexattr_t *) NULL);  //初始化鎖

pthread_cond_init(&acond, (const pthread_condattr_t *) NULL);   //初始化條件變數

 

 

pthread_mutex_lock(&alock);

……

pthread_cond_signal(&acond);  //執行緒A中傳送訊號

…….

pthread_mutex_unlock(&alock);

 

 

 

struct timeval now;

struct timespec outtime;

int timeout_ms = 20;

int nsec;

gettimeofday(&now, NULL);

nsec = now.tv_usec * 1000 + (timeout_ms % 1000) * 1000000;

outtime.tv_sec = now.tv_sec + nsec/1000000000 + timeout_ms/1000;

outtime.tv_nsec = nsec % 1000000000;

pthread_mutex_lock(&alock);

//ret = pthread_cond_timedwait(&acond, &alock, &outtime); //執行緒B中等待訊號,signal傳送訊號之前,一直阻塞在這裡,如果過了20ms signal還沒有發訊號, 則開始執行,不再等待, 本質上加了一個超時檢測。

ret = pthread_cond_wait(&acond, &alock);  //執行緒B中等待訊號,signal傳送訊號之前,一直阻塞在這裡。

if (ret != 0) {

ALOGE("%s: failed cond ! %d\n", __func__, ret);

}

pthread_mutex_unlock(&alock);

 

 

3.  訊號量

 

作用: 保證執行緒或程序間的同步

 

訊號量用在多執行緒多工同步的,一個執行緒完成了某一個動作就通過訊號量告訴別的執行緒,別的執行緒再進行某些動作。

 

 

#include <semaphore.h>     //標頭檔案

……

static  sem_t  sem_sync;   //定義變數

…….

sem_init(&sem_sync, 0, 0);   //初始化

……

sem_post(&sem_sync);   //執行緒A傳送訊號量

…….

sem_wait(&sem_sync);   //執行緒B等待訊號量, post訊號之前一直阻塞在這裡