《Unix/Linux系統程式設計》第四章學習筆記
學習筆記
20191318 王澤文
《Unix/Linux系統程式設計》
第四章 併發程式設計
本章論述了併發程式設計,介紹了平行計算的概念,指出了平行計算的重要性;比較了順序演算法與並行演算法, 以及並行性與併發性;解釋了執行緒的原理及其相對於程序的優勢;解釋了死鎖問題, 並說明了如何防止併發程式中的死鎖問題;討論了訊號量, 並論證了它們相對千條件變數的優點;還解釋了支待 Linux 中執行緒的獨特方式。
平行計算
基於分治原則(如二叉樹查詢和快速排序等)的演算法經常表現出高度的並行性,可通過使用並行或併發執行米提高計算速度。平行計算是一種計算方案,它嘗試使用多個執行並行演算法的處理器 更快速地解決問題。
井行性與併發性
並行演算法只識別可並行執行的任務,但是它沒有規定如何將任務對映到處理元件。在理想情況下,並行演算法中的所有任務都應該同時實時執行。然而,真正的並行執行只能在有多個處理元件的系統中實現,比如多處理牉或多核系統。在單CPU系統中,一次只能執行一個任務。在這種情況下,同的任務只能併發執行,即在邏輯上並行執行。在單CPU系統中併發性是通過多工處理來實現的。
執行緒
執行緒是某程序同一地址空間上的獨立執行單元。建立某個程序就是在一個唯一地址空間建立一個執行緒。當某程序開始時,就會執行該程序的主執行緒。如果只有一個主執行緒,那麼程序和執行緒實 際上並沒有區別。但是, 主執行緒可能會建立其他執行緒。 每個執行緒又可以建立更多的執行緒等。 某程序的所有執行緒都在該程序的相同地址空間中執行, 但每個執行緒都是一個獨立的執行單元。
執行緒優點
- 執行緒建立和切換速度更快:若要在某個程序中建立執行緒,作業系統不必為新的執行緒分配記憶體和建立頁表,因為執行緒與程序共用同一個地址空間。所以,建立執行緒比建立程序更快。
- 執行緒的響應速度更快:一個程序只有一個執行路徑。當某個程序被掛起時,幫個程序都將停止執行。相反,當某個執行緒被掛起時,同一程序中的其他執行緒可以繼續執行。
- 執行緒更適合井行計算:平行計算的目標是使用多個執行路徑更快地解決間題。基於分治原則(如二叉樹查詢和快速排序等)的演算法經常表現出高度的並行性,可通過使用並行或併發執行來提高計算速度。
執行緒缺點
- 由於地址空間共享,執行緒需要來自使用者的明確同步。
- 許多庫函式可能對執行緒不安全
- 在單CPU系統上,使用執行緒解決間題實際上要比使用順序程式慢,這是由在執行時建立執行緒和切換上下文的系統開銷造成的。
執行緒操作
執行緒的執行軌跡與程序類似。執行緒可在核心模式或使用者模式下執行。在使用者模式下,執行緒在程序的相同地址空間中執行,但每個執行緒都有自己的執行堆疊。執行緒是獨立的執行單元,可根據作業系統核心的排程策略,對核心進行系統呼叫,變為桂起啟用以繼續執行等。為了利用執行緒的共享地址空間,作業系統核心的排程策略可能會優先選擇同一程序中的執行緒,而不是不同程序中的執行緒。
Pthread併發程式設計
Pthread庫提供了用於執行緒管理的以下APT。
pthread_create(thread, attr, function, arg): create thread
pthread_exit(status):terminate thread
pthread_cancel(thread) : cancel thread
pthread_attr_init(attr) : initialize thread attributes
pthread_attr_destroy(attr): destroy thread attribute
- 使用pthread_ create()函式建立執行緒。
int pthread_create (pthread_t *pthread_id,pthread_attr_t•attr,void * (*func) (void *), void *arg);
如果成功則返回0,如果失敗則返回錯誤程式碼。- pthread_id是指向pthread_t型別變員的指標。它會被作業系統核心分配的唯一執行緒ID填充。在POSIX中,pthread_t是一種不透明的型別。程式設計師應該不知道不透明物件的內容,因為它可能取決千實現情況。執行緒可通過pthread_self()函式獲得自己的ID。在Linux中,pthread_t型別被定義為無符號長整型,因此執行緒ID可以列印為%lu。
- attr是指向另一種不透明資料型別的指標,它指定執行緒屬性。
- func是要執行的新執行緒函式的人口地址。
- arg是指向執行緒函式引數的指標,可寫為:
void *func(void *arg)
,attr引數使用:- 定義一個pthread展性變址pt:hread_attr_tattr。
- 用pthread_attr_init(&attr)初始化屈性變掀。
- 設定屬性變垃並在pthread_ create()呼叫中使用。
- 必要時,通過pthread_attr_destroy(&attr)釋放attr資源。
- 執行緒ID 是一種不透明的資料型別,取決於實現悄況。因此,不應該直接比較執行緒ID。如果需要,可以使用
pthread_ equal()
函式對它們進行比較。
int pthread_equal (pthread_t tl, pthread_t t2);
- 執行緒函式結束後,執行緒即終止。或者,執行緒可以呼叫函式
int pthraad_axit {void *status)
- 一個執行緒可以等待另一個執行緒的終止, 通過:
int pthread_join (pthread_t thread, void **status__ptr);
終止執行緒的退出狀態以status_ptr
返回。 - 在 Pthread中,鎖被稱為互斥量,意思是相互排斥。互斥變呈是用
ptbread_mutex_t
型別宣告的在使,用之前必須對它們進行初始化。有兩種方法可以初始化互斥址。- 靜態方法,
pthreaa—mutex_t m = PTHREAD_MUTEX_INITIALIZER
; 定義互斥量 m, 並使用預設屬性對其進行初始化。 - 動態方法,使用
pthread_ mutex _init()
函式
- 靜態方法,
- 條件變數:作為鎖,互斥量僅用於確保執行緒只能互斥地訪間臨界區中的共享資料物件。在Pthread中,使用型別
pthread_cond_t
來宣告條件變拉,而且必須 在使用前進行初始化。與互斥變數一樣,條件變數也可以通過兩種方法進行初始化。- 靜態方法:
pthread_cond_t con= PTHREAD_COND_INITIALIZER
;定義一個條件變屾con,並使用預設屬性對其進行初始化。 - 動態方法:使用
pthread_cond_init()
函式,可通過attr引數設定條件變數。為簡便起見,我們總是使用NULLattr引數作為預設屬性。
- 靜態方法:
其他
程式設計實踐