Linux多執行緒編程(二)

  • 2019 年 10 月 6 日
  • 筆記

一番碼客 : 挖掘你關心的亮點。 http://efonfighting.imwork.net

4 – 執行緒的數據處理5 – 執行緒的同步和互斥:互斥鎖訊號量條件變數參考

4 – 執行緒的數據處理

在單執行緒的程式里,有兩種基本的數據:全局變數和局部變數。但在多執行緒程式里,還有第三種數據類型:執行緒數據(TSD: Thread-Specific Data)。

執行緒數據和全局變數很象,在執行緒內部,各個函數可以象使用全局變數一樣調用它,但它對執行緒外部的其它執行緒是不可見的。也就是說,我們要在執行緒中使用全局變數,但是這個全局變數在各個執行緒中是獨立的。

例如我們常見的變數errno,它返回標準的出錯資訊。它顯然不能是一個局部變數,幾乎每個函數都應該可以調用它;但它又不能是一個全局變數,否則在A執行緒里輸出的很可能是B執行緒的出錯資訊。

要實現諸如此類的變數,我們就必須使用執行緒數據。我們為每個執行緒數據創建一個鍵,它和這個鍵相關聯,在各個執行緒里,都使用這個鍵來指代執行緒數據,但在不同的執行緒里,這個鍵代表的數據是不同的,在同一個執行緒里,它代表同樣的數據內容。

相關的函數和結構:

  • **pthread_key_t key ** : 指向一個鍵值的指針 pthread_key_t的定義為typedef int pthread_key_t;不論哪個執行緒調用了
  • **destructor_function ** : 這是一個銷毀函數,它是可選的,可以為 NULL,為 NULL 時,則系統調用默認的銷毀函數進行相關的數據註銷。如果不為空,則在執行緒退出時(調用 pthread_exit() 函數)時將以 key 鎖關聯的數據作為參數調用它,以釋放分配的緩衝區,或是關閉文件流等。
  • **pthread_setspecific/pthread_getspecific ** : 設置和獲取執行緒變數的值。

5 – 執行緒的同步和互斥:

互斥鎖

互斥鎖用來保證一段時間內只有一個執行緒在執行一段程式碼。一般使用流程:

  • 定義一個鎖(pthread_mutex_t)
  • 初始化鎖(pthread_mutex_init)
  • 使用pthread_mutex_lock/pthread_mutex_unlock進行鎖定和解鎖。

注意:加鎖、解鎖之間不能return或break,否則會死鎖。

訊號量

訊號量是一種特殊的變數,本質上是一個非負的整數計數器,可以被增加或減少,但系統保證對該變數的訪問是原子操作(這能控制多個執行緒操作同一資源時的順序問題)。如果一個程式中有多個執行緒試圖改變一個訊號量的值,系統將保證所有的操作都將依次進行。

這裡需要引入新的頭文件semaphore.h

  • sem_init 初始化訊號量。該函數初始化由sem指向的訊號對象,設置它的共享選項,並給它一個初始的整數值。pshared控制訊號量的類型,如果其值為0,就表示這個訊號量是當前進程的局部訊號量,否則訊號量就可以在多個進程之間共享,value為sem的初始值。調用成功時返回0,失敗返回-1.
  • sem_post ( sem_t *sem ) 該函數用於以原子操作的方式將訊號量的值加1。當有執行緒阻塞在這個訊號量上時,調用這個函數會使其中的一個執行緒不在阻塞。
  • sem_wait( sem_t *sem ) 被用來阻塞當前執行緒直到訊號量sem的值大於0,解除阻塞後將sem的值減1,表明公共資源經使用後減少。
  • sem_destroy 該函數用於清理用完的訊號量。

條件變數

互斥鎖是用來給資源上鎖的,而條件變數是用來等待而不是用來上鎖的。

條件變數用來自動阻塞一個執行緒,直到某特殊情況發生為止。

通常條件變數和互斥鎖同時使用。

和條件變數使用有關的幾個重要函數:

/*  初始化與銷毀:  條件變數採用的數據類型是pthread_cond_t, 在使用之前必須要進行初始化, 這包括兩種方式:  - 靜態: 可以把常量PTHREAD_COND_INITIALIZER給靜態分配的條件變數.  - 動態: pthread_cond_init函數, 是釋放動態條件變數的記憶體空間之前, 要用pthread_cond_destroy對其進行清理.  */  int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);  int pthread_cond_destroy(pthread_cond_t *cond);    /*  等待條件:  等待條件函數等待條件變為真, 傳遞給pthread_cond_wait的互斥量對條件進行保護, 調用者把鎖住的互斥量傳遞給函數. 函數把調用執行緒放到等待條件的執行緒列表上, 然後對互斥量解鎖, 這兩個操作是原子的. 這樣便關閉了條件檢查和執行緒進入休眠狀態等待條件改變這兩個操作之間的時間通道, 這樣執行緒就不會錯過條件的任何變化.  當pthread_cond_wait返回時, 互斥量再次被鎖住.  */  int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);  int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);    /*通知條件:  這兩個函數用於通知執行緒條件已經滿足. 調用這兩個函數, 也稱向執行緒或條件發送訊號.  必須注意, 一定要在改變條件狀態以後再給執行緒發送訊號.  */  int pthread_cond_signal(pthread_cond_t *cond);  int pthread_cond_broadcast(pthread_cond_t *cond);  //解除所有執行緒的阻塞  

參考

  • https://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/
  • https://cloud.tencent.com/developer/article/1193996
  • https://blog.csdn.net/zsf8701/article/details/7843837
  • Linux 執行緒調度與優先順序: https://www.cnblogs.com/xiaojianliu/p/9689118.html
  • Linux執行緒同步——條件變數:https://www.cnblogs.com/liangf27/p/9493722.html

免費知識星球: 一番碼客-積累交流 微信公眾號:一番碼客 微信:Efon-fighting 網站:http://efonfighting.imwork.net