互斥變數是用 pthread_mutex_t 資料型別表示的。下面幾個函式可操作互斥量。
#include
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
/* 所有函式的返回值:若成功,返回 0;否則,返回錯誤編號 */
使用互斥量前必須先對它進行初始化,可把它設定為常量 pthread_mutex_initializer(只適用於靜態分配的互斥量),也可以通過 pthread_mutex_init 函式進行初始化。要用預設的屬性初始化互斥量,只需把 pthread_mutex_init 的引數 attr 設為 null。如果互斥量是動態分配的,則釋放記憶體前需要呼叫 pthread_mutex_destroy。
函式 pthread_mutex_lock 和 pthread_mutex_unlock 可分別對互斥量進行加鎖和解鎖。如果互斥量已經上鎖,呼叫執行緒將阻塞直到互斥量被解鎖。如果執行緒不希望被阻塞,可以使用 pthread_mutex_trylock 嘗試對互斥量加鎖。若呼叫 pthread_mutex_trylock 時互斥量未上鎖,則該函式就鎖住互斥量,然後直接返回 0,否則該函式就會失敗,然後返回 ebusy。
下面這段**描述了如何用互斥量來保護某個資料結構。當有多個執行緒要訪問動態分配的物件時,可以在物件中嵌入引用計數,確保在所有使用該物件的執行緒完成資料訪問之前,該物件的記憶體空間不會被釋放。
#include
#include
struct foo;
struct foo* foo_alloc(int id)
/*...continue initialization...*/
}return foop;
}void foo_hold(struct foo *foop)
void foo_rele(struct foo *foop)else
}
為避免執行緒在獲取鎖時永久阻塞,可以使用函式 pthread_mutex_timedlock。
#include
#include
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr);
/* 返回值:若成功,返回 0;否則,返回錯誤編號 */
該函式與 pthread_mutex_lock 基本等價,但它允許繫結執行緒阻塞時間。當達到超時時間時,它不會對互斥量進行加鎖,而是返回錯誤碼 etimedout。這裡的時間引數是乙個絕對時間。
下面這個示例通過對已有的互斥量進行再次加鎖(這通常會造成死鎖)來演示了如何用 pthread_mutex_timedlock 來避免永久阻塞。
#include
#include
#include
#include
#include
void pr_time(struct timespec tout)
int main(void)
編譯後執行:
$ gcc timeoutlock.c -lpthread -lrt -o timeoutlock.out
$ ./timeoutlock.out
mutex is locked
current time is: 10:37:07 am
current time is: 10:37:12 am
can't lock mutex again: connection timed out
說完互斥量,接下來再說說讀寫鎖。
讀寫鎖也稱共享互斥鎖,它能在讀取資料頻率遠高於寫資料時提供比互斥量更高的併發性。當讀寫鎖在寫模式下時,它所保護的資料就可以被安全地修改,因為一次只有乙個執行緒可以擁有寫模式的鎖。而當它在讀模式下時,只要執行緒先獲取了讀模式下的讀寫鎖,該鎖所保護的資料就可以同時被多個獲得讀模式鎖的執行緒讀取。為避免讀模式鎖長期占用,一般如果有乙個執行緒試圖以寫模式獲取鎖時,讀寫鎖通常會阻塞隨後的讀模式鎖請求。
與互斥量相同,讀寫鎖在使用前必須初始化,在釋放其底層記憶體前必須銷毀。
#include
int pthread_rwlock_init( pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock *rwlock);
/* 兩個函式返回值:若成功,返回 0;否則,返回錯誤編號 */
attr 引數是讀寫鎖的屬性,為 null 表示使用預設屬性。xsi 擴充套件中也定義了 pthread_rwlock_initializer 常量,用來對靜態分配的讀寫鎖進行初始化。
可以呼叫 pthread_rwlock_rdlock 和 pthread_rwlock_wrlock 分別在讀模式和寫模式下鎖定讀寫鎖,這兩種方式都可以呼叫 pthread_rwlock_unlock 來進行解鎖。
#include
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
/* 三個函式返回值:若成功,返回 0;否則,返回錯誤編號 */
各種實現可能會對共享模式下可獲取的讀寫鎖的次數進行限制,所以應該檢查 pthread_rwlock_rdlock 的返回值。
single unix specification 還定義了讀寫鎖原語的條件版本和帶有超時的讀寫鎖函式。
#include
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_timedrdlock( pthread_rwlock_t *restrict rwlock,
const struct timespec *restrict tsptr);
int pthread_rwlock_timedwrlock( pthread_rwlock_t *restrict rwlock,
const struct timespec *restrict tsptr);
/* 所有函式返回值:若成功,返回 0;否則,返回錯誤編號 */
可以獲取鎖時,前兩個函式返回 0,否則,它們返回錯誤 ebusy。後兩個函式如果在到達指定的時刻時還不能獲取鎖就將返回 etimedout 錯誤。
競爭與同步 互斥量 讀寫鎖
由於執行緒之間的絕大多數資源都是共享的,當多個執行緒同時訪問乙個資源時,可能會出現資料不完整 不一致的情況,此時就需要多個執行緒協調訪問資源 競爭訪問,需要用於互斥技術 最終達到資料一致 完整 同步 也叫互斥鎖,當互斥量處於鎖定狀態時,其他執行緒加鎖會處於阻塞狀態,只有鎖被開啟時,被阻塞的執行緒才能...
互斥鎖機制,互斥鎖與讀寫鎖區別
互斥鎖 mutex,用於保證在任何時刻,都只能有乙個執行緒訪問該物件。當獲取鎖操作失敗時,執行緒會進入睡眠,等待鎖釋放時被喚醒 讀寫鎖 rwlock,分為讀鎖和寫鎖。處於讀操作時,可以允許多個執行緒同時獲得讀操作。但是同一時刻只能有乙個執行緒可以獲得寫鎖。其它獲取寫鎖失敗的執行緒都會進入睡眠狀態,直...
互斥鎖與讀寫鎖使用
sync.mutex和sync.rwmutex是go語言底層基礎物件,用於構建多個goroutine間的同步邏輯,當多個協程需要對共享資料讀寫時用到。具體實現極為簡潔,效能也 舉例 1.多個協程操作同乙個檔案 2.生產者消費者模型 具體例項我就以最簡單的列印方式說明互斥鎖 func print t ...