互斥量是二值鎖,核心操作 lock/unlock。本文詳細演示互斥量保護共享數據讀寫,對比無鎖時的數據競態,並深入分析 pthread_mutex_lock 重複加鎖導致的死鎖風險與 pthread_mutex_trylock 非阻塞避免方案。
| 函數 | 作用 | 關鍵行為 |
|---|---|---|
pthread_mutex_init | 初始化 | 屬性可為 NULL(默認),返回 0 成功 |
pthread_mutex_destroy | 銷毀 | 僅釋放鎖資源,不檢查是否被鎖定 |
pthread_mutex_lock | 加鎖(阻塞) | 已鎖定時阻塞;同一線程重複加鎖 → 死鎖 |
pthread_mutex_trylock | 嘗試加鎖(非阻塞) | 已鎖定時返回 EBUSY,不阻塞,避免死鎖 |
pthread_mutex_unlock | 解鎖 | 僅持有者可解鎖,否則未定義行為 |
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int data = 0;
void read_data(char* str) {
pthread_mutex_lock(&mutex);
printf("[%s] start reading data\n", str);
sleep(1); printf("[%s] data = %d\n", str, data);
printf("[%s] end reading data\n", str);
pthread_mutex_unlock(&mutex);
}
void write_data(char* str) {
pthread_mutex_lock(&mutex);
printf("[%s] start writing data\n", str);
sleep(1); data++; printf("[%s] data = %d\n", str, data);
printf("[%s] end writing data\n", str);
pthread_mutex_unlock(&mutex);
}
Thread_1 start reading data Thread_2 start writing data Thread_1 data = 0 // 寫未完成,讀到舊值 Thread_1 end reading data Thread_2 data = 1 ...
Thread_1 start reading data Thread_1 data = 0 Thread_1 end reading data Thread_2 start writing data Thread_2 data = 1 Thread_2 end writing data Thread_1 start reading data Thread_1 data = 1 // 讀到最新值 ...
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex); // 此處永久阻塞!默認鎖類型不支持遞歸
原因:默認 PTHREAD_MUTEX_DEFAULT 不記錄擁有者遞歸計數,二次 lock 視為爭用而阻塞,等待自己釋放 → 死等。
int res = pthread_mutex_trylock(&mutex);
if (res == 0) { /* 獲取成功 */ pthread_mutex_unlock(&mutex); }
else if (res == EBUSY) { /* 鎖忙,含自己持有 */ /* 不阻塞,繼續邏輯 */ }
運行結果:第二次 trylock 返回 EBUSY,線程繼續執行,無死鎖,程序正常結束。
sem_post)、生產者-消費者緩衝區槽位管理。LOCK/UNLOCK 宏或 C++ lock_guard,確保異常安全。pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) 開發階段啟用錯誤檢查鎖,自動檢測重複加鎖、非擁有者解鎖等錯誤。