多 thread 程式有一個好處是全域變數在 process 內是共用的,不需要跨 process 共用機制,但存取時要避免衝突產生,其中一種方式是使用 mutex (mutual exclusion) 來建立 critical section,來同步共用資源的使用。
如果變數只是一個 int 且只有一個 thread 會改變它,其它都只是讀 => 沒有同步問題
mutex 只有兩種狀態:locked 及 unlocked。一個 mutex,只有一個 thread 可以取得 lock,此時只有它可以 unlock。其它 thread 要 lock 需等候。一般不能有下列行為:
- 一個 thread lock 同一個 mutex 兩次:可能產生 deadlock (Linux 預設) 或回傳錯誤碼 EDEADLK。
- 一個 thread unlock 不是它 lock 的 mutex
- 一個 thread unlock 還沒 lock 的 mutex
建立
mutex 是資料型態為 pthread_mutex_t 的變數,可以靜態或動態初始化:
靜態,初始化為 unlock。
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
動態初始化,可設 attr。如用預設值,attr 可為 NULL。不再使用時,應該要回到 unlocked 狀態後 destroy。
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); int pthread_mutex_destroy(pthread_mutex_t *mutex);
成功時回傳 0 或正的錯誤碼。
pthread_mutexattr_init()pthread_mutexattr_destroy()
Locking 和 Unlocking
pthread_mutex_lock(pthread_mutex_t *mutex):等候到 mutex unlock 後,lock 並馬上 return。pthread_mutex_unlock(pthread_mutex_t *mutex):unlock 自己 thread 之前 lock 的 mutex。
另外還有兩種 lock 的變形
pthread_mutex_trylock():如果已經 lock,回 EBUSY。
pthread_mutex_timedlock():等候 abstime 還未取得 lock,回 ETIMEDOUT。
參考
- 《The Linux Programming Interface》chap. 30
- https://computing.llnl.gov/tutorials/pthreads/#Mutexes
- semaphore 也可以建立 critical section,但效能沒 mutex 好。
- 比較 pthread_spin_lock() (pthread_spin_trylock()):適合 lock 的時間極短 (例如只是計數加 1),很少發生 contention,常用到而有可能成為效能瓶頸。spinlock 無關乎 thread 切換,lock 失敗時 thread 不會造成 sleep,一可以取得時可以馬上取得 (前提是沒有 thread 切換,但是事實上需要另一個釋出 lock 的 thread,特別是 uni-processor,所以勢必忙於等待 thread 切換,反而可能等候更久)。unlock 時不會檢查其它 thread 是否在等待需喚醒,只是一個 atomic write instruction。
- pthread_cond_init()
- barrier
- pthread_rwlock_init():
- Read lock 只要在沒有 Write lock 就可以,可有多個。
- Write lock 要在沒有任何 Read 和 Write lock 下才可以,可能因為一直有新舊 Read lock 而導致 starvation。
- mutex 用在跨 process:mutex between processes
沒有留言:
張貼留言