####### 線程同步
當多個控制線程共享相同的內存時,需要確保每個線程看到一致的數據視圖。
如果使用的變量都是其他線程不會讀取和修改的,那么就不會存在一致性問題。但是,當一個線程可以修改的變量,其他線程也可以讀取或者修改時,就需要對這些線程進行同步,確保它們在訪問變量的存儲內容時不會訪問到不一致的值。
當一個線程修改變量時,其他線程在讀取這個變量時可能會看到一個不一致的值,在變量修改時間多余一個存儲器訪問周期的處理器結構中,當存儲器讀與存儲器寫這兩個周期交叉時,這種不一致就會出現。
比如兩個線程試圖在同一時間修改同一變量,也需要進行同步。考慮變量增量操作的情況,增量的操作通常分為3步:
【1】從內存單元讀入到寄存器
【2】在寄存器中對變量做增量操作
【3】把新的值寫回內存單元
如果兩個線程試圖幾乎在同一時間對同一個變量做增量操作而不進行同步的話,結果就可能出現不一致,變量可能比原來增加了1,也有可能比原來增加了2。具體增加多少,要取決于第二個線程開始操作時獲取的數值。
互斥量
互斥量從本質上說是一把鎖,在訪問共享資源前加鎖,在訪問完成后解鎖,對互斥量進行加鎖后,任何其他試圖再次對互斥量加鎖的線程都會被阻塞,直到當前線程釋放該互斥鎖。如果釋放互斥量時有一個以上的線程被阻塞,那么所有該鎖上的阻塞線程都會變成可運行的狀態,第一個變為運行的線程就可以對互斥量加鎖,其他線程就會看到互斥量依然是鎖著的,只能回去再次等待它重新變為可用。
-
初始化與銷毀
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr attr); int pthread_mutex_destroy(pthread_mutex_t *mutex); 2個函數返回值:成功返回0,否則返回錯誤編號
可以用2種方式初始化:
- 靜態變量的互斥鎖使用
PTHREAD_MUTEX_INITIALIZER
初始化 - 其他使用
pthread_cond_init
函數對它進行初始化
- 靜態變量的互斥鎖使用
-
加鎖
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex) int pthread_mutex_trylock(pthread_mutex_t *mutex) 2個函數返回值:成功返回0,否則返回錯誤編號
如果互斥量已經上鎖,調用線程將阻塞直到互斥量被解鎖。如果調用線程不想被阻塞,那么可以用trylock加鎖,互斥量被鎖住時,trylock將失敗返回EBUSY。
-
解鎖
#include <pthread.h> int pthread_mutex_unlokc(pthread_mutex_t *mutex)
-
代碼示例:
多個線程對全局資源的訪問#include <pthread.h> #define THREAD_NUM 20 // 線程數量 int num = 0; // 全局資源 pthread_mutex_t lock; void* thr_fn(void* arg) { pthread_mutex_lock(&lock); num++; printf("%lu: %d\n", pthread_self(), num); pthread_mutex_unlock(&lock); } int main() { int i = 0; pthread_t tid; pthread_mutex_init(&lock, NULL); for (; i != THREAD_NUM; i++) pthread_create(&tid, NULL, thr_fn, NULL); sleep(1); }
死鎖
參考資料
[1]《UNIX環境高級編程》[美] W. Richard Stevens Stephen A. Rago