執行緒同步方法:
- 互斥鎖
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必須放在lock和unlock之間
執行某種操作
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訊號之前一直阻塞在這裡