linux執行緒基礎概念及多執行緒程式設計
Linux中執行緒的概念:
首先,Linux中並不存在真在的執行緒。Linux中的執行緒是使用程序來模擬的。在一個程序需要同時執行多個執行流時,linux並不是開闢多個執行緒來執行,而是通過多個程序來模擬多個執行緒。
Linux中執行緒的實現原理:
首先先看一下張圖:
此時共有4個執行緒屬於同一個程序,他們的task_struct(Linux中為PCB)不同,但是對映的虛擬地址空間和頁表是相同的。所以說Linux中的的執行緒就是——多個PCB對映同一塊虛擬地址空間,使得同一個程序中不同的執行流能夠同時執行。因此可以總結出同一程序不同執行緒的資源分配情況:
共享 | 私有 |
虛擬地址空間中的程式碼段、資料段 | 執行緒ID |
檔案描述符表(一個執行緒打開了檔案,其他執行緒也可以看到此檔案的描述符) | 一組暫存器(儲存著此執行緒的上下文資訊,上下文中儲存著各種計數器的值,程式計數器和棧指標) |
每種訊號的處理方式 | 棧(執行時棧) |
在同一個工作目錄下 | errno(執行緒異常退出時的錯誤退出碼) |
使用者ID和執行緒組ID | 訊號遮蔽字 |
排程優先順序 |
執行緒的優缺點:
優點:
-
相比程序,更加節省系統資源(虛擬地址空間、頁表、實體記憶體中的程式碼和資料都是共享的)。
-
執行緒間切換,系統的工作量很少(切換程序的時候需要切換程序上下文、地址空間、頁表。執行緒切換隻需要切換上下文,也不用切換cache(記憶體和暫存器之間的一個硬體))。
-
建立一個新執行緒的代價,比建立一個程序的代價小得多。
-
執行緒間共享資料更加容易。
-
能夠充分利用多處理器的可並行數量。
-
在等待慢速的I/O操作結束的同時,程式可以執行其他的計算任務。
-
計算密集型應用,為了能在多處理器系統上執行,可以將計算分解到多個執行緒中來實現。
-
I/O密集型應用,為了提高效能,將I/O操作重疊。執行緒可以同時等待不同的I/O操作。
缺點:
1.效能損失
一個很少被外部事件阻塞的計算密集型執行緒往往無法與其他執行緒共享一個處理器。如果計算密集型執行緒的數量比可用的處理器多,那麼就有可能造成較大的效能損失,這裡的效能損失指的是作業系統增加了額外的同步和排程開銷,而可用的資源不變。
2.健壯性降低
由於執行緒是共享同一塊虛擬地址空間的,在執行期間,因時間分配上的細微偏差或者因共享了不該共享的變數而造成不良影響的可能性是很大的,也就是說執行緒之間是缺乏保護的。
3.缺乏訪問控制
當線上程中呼叫某些函式(OS函式,處理signal函式,呼叫kill/exit函式),可能會導致執行緒退出,從而使所有的執行緒都異常退出。
4.程式設計難度高
執行緒共用同一塊虛擬地址空間,勢必在處理多執行緒時會有訪問同一個資源等問題,此時就涉及到共享資源的處理。
執行緒相關概念:
- Linux中的執行緒概念只是模擬執行緒。對於Linux系統來說,並不存線上程一說。因此,執行緒的概念只有在使用者態才有。
- NLWP:當前執行緒組中的執行緒個數。
- 程序是資源分配的單位,執行緒是系統排程的基本單位。
- bash中輸入ps -aL | grep your_thread_name (L表示檢視執行緒)此命令可以檢視同一程序的所有執行緒。
- 系統打印出的tid轉成16進位制之後可以看到,tid本質上來說就是地址。
- LWP:執行緒又被稱作LWP(Light WeightedProcess)輕量級程序。是執行緒的ID,是使用gettid()函式的返回值。連結執行緒庫函式的時候,需要使用“-Ipthread”選項
- 與執行緒有關的函式,大多數是以pthread_開頭的
- 執行緒組(tgid):由於執行緒概念的引入,一個程序可能對應多個PCB,POSIX標準又要求所有的執行緒在呼叫getpid函式的時候返回相同的程序ID,所以就有了執行緒組的概念。
- 使用者層面看到的pid,對應的是底層核心中的tgid。而使用者層面的tid,對應在核心之中則是pid欄位。
- 一個使用者態的程序,內部對應著N個PCB,tgid通常是執行緒組的第一個執行緒(主執行緒)
- LWP實則是pid。
- 執行緒組中的第一個執行緒,在使用者態被稱為主執行緒,在核心中被稱為group leader。核心在建立第一個執行緒的時候,會將執行緒組的ID值,設定成第一個執行緒的執行緒ID,Group_Leader指標則指向自身,即主線執行緒的程序描述符。
- 執行緒租記憶體在一個執行緒,它的ID等於程序ID,而該執行緒就是該執行緒組的主程序。
- 執行緒沒有父子的概念,只有主執行緒,沒有父子執行緒之分
- 程式開始執行之後,哪個程序先執行由排程機決定,執行緒也是同理
- pythread_self()函式可以用來獲取當前執行緒自身的tid。
執行緒的建立與控制:
POSIX執行緒:
是POSIX的執行緒標準,它定義了一套建立和操縱執行緒的一套API,以pthread.h標頭檔案和一個執行緒庫來實現,而且其中的函式均以“pthead_”開頭。gcc或g++在連結這些執行緒函式庫的時候,需要使用“-Ipthread”選項(pthread是共享庫檔案)。