2014年11月9日 星期日

pthread mutex

thread 程式有一個好處是全域變數在 process 內是共用的,不需要跨 process 共用機制,但存取時要避免衝突產生,其中一種方式是使用 mutex (mutual exclusion) 來建立 critical section,來同步共用資源的使用。

如果變數只是一個 int 且只有一個 thread 會改變它,其它都只是讀 => 沒有同步問題

mutex 只有兩種狀態:locked 及 unlocked。一個 mutex,只有一個 thread 可以取得 lock,此時只有它可以 unlock。其它 thread 要 lock 需等候。一般不能有下列行為:

  1. 一個 thread lock 同一個 mutex 兩次:可能產生 deadlock (Linux 預設) 或回傳錯誤碼 EDEADLK。
  2. 一個 thread unlock 不是它 lock 的 mutex
  3. 一個 thread unlock 還沒 lock 的 mutex
Mutex Deadlock: 有兩個以上的 mutex,當多個 thread 同時 lock 這些 mutex 時,由於 lock 哪個 mutex 的順序關係而造成 deadlock。

建立

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。

參考

  1. The Linux Programming Interface》chap. 30
  2. https://computing.llnl.gov/tutorials/pthreads/#Mutexes
  3. semaphore 也可以建立 critical section,但效能沒 mutex 好。
  4. 比較 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。
  5. pthread_cond_init()
  6. barrier
  7. pthread_rwlock_init():
    • Read lock 只要在沒有 Write lock 就可以,可有多個。
    • Write lock 要在沒有任何 Read 和 Write lock 下才可以,可能因為一直有新舊 Read lock 而導致 starvation。
  8. mutex 用在跨 process:mutex between processes

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...