Linux之線程小議

1.線程與進程的關係

說到線程概念,必須先說明進程。進程是一個運行中的程序,在操作系統中,一個程序運行起來後就會被加載到內存中。操作系統創建了一個進程描述符(PCB)對程序的運行進行描述控制。因此進程就是PCB,在Linux下用task_struct結構體來描述。Linux系統下,用進程PCB來模擬線程,因此Linux下一個線程就是一個輕量級進程。如果說PCB稱爲了線程,那麼進程就是線程組。一個進程中至少有一個或多個線程。

因爲Linux下PCB是一個線程,因此線程是CPU調度的基本單位。因爲程序運行時候分配資源,進程(線程組)是資源分配的基本單位。進程中的所有線程共用一個虛擬地址空間,因此可以共享進程的代碼段和數據段又因爲線程之間數據的共享,所以線程之間進行通信就變得極爲簡單

因爲每個線程都是PCB,是CPU調度的基本單位,因此線程可以同時運行,但不會造成調用棧混亂,主要是因爲每個線程都有自己的獨有數據

  1. 上下文數據
  2. 信號屏蔽字
  3. errno
  4. 線程標識符

既然多進程可以並行處理任務,多線程也可以。其優缺點分析如下(根據具體使用情況):
多線程的優點: 因爲線程共享虛擬地址空間,線程間通信簡單,線程的創建/銷燬成本更低,線程的執行粒度更細。
多線程缺點: 線程缺乏訪問控制(可以訪問虛擬地址空間中的任何一塊數據);但線程的某些錯誤會導致整個進程退出,即健壯性較低。
注意:線程的數量也並非越多越好,因爲過多的話會導致切換頻繁,在一定程度上反而會降低性能。

2.線程控制

操作系統並沒有提供直接的創建線程的接口(用戶創建線程很麻煩),因此前輩們實現了一套線程控制接口供用戶使用。因此我們說創建的線程是一個用戶態的線程,但是在內核對應有一個輕量級進程實現程序的調度運行。

2.1 線程創建

int pthread_create(pthread_t *thread, pthread_addr_t *arr,void* (*start_routine)(void *), void *arg);

//thread    :用於返回創建的線程的ID
//arr         : 用於指定的被創建的線程的屬性,上面的函數中使用NULL,表示使用默認的屬性
//start_routine      : 這是一個函數指針,指向線程被創建後要調用的函數
//arg        : 用於給線程傳遞參數,在本例中沒有傳遞參數,所以使用了NULL

2.2 線程終止
如果需要只終止某個線程而不終止整個進程,可以有以下三種方法:

  1. 從線程函數return。這種方法對主線程不適用,從main函數return相當調用exit.
    (在main中return,退出整個進程;在普通入口函數中return,只是退出調用線程)
  2. 線程可以調用pthread_exit來終止自己(退出調用線程)
  3. pthread_cancel用來取消指定線程,也可以取消自己。

pthread_exit()函數

//功能:線程終止
//原型:
void pthread_exit(void* value_ptr);
//參數:
 value_ptr:不能指向一個局部變量
//返回值:無。跟進程一樣,線程結束的時候無法返回到它的調用者。

pthread_cancel()函數

//功能:取消一個執行中的線程
//原型:
int pthread_cancel(pthread_t thread);
//參數:
 thread: 線程ID
//返回值:成功返回0,失敗返回錯誤碼

2.3 線程等待
爲什麼要進行線程等待呢?簡言之,線程退出後可能會產生“殭屍線程”,所以要等待,以免造成資源泄露。換句話說,即:
等待指定線程退出,就是要獲取指定線程的返回值,回收線程資源。因爲一個線程被創建後,默認有一個屬性爲joinable,處於這個屬性的線程必須被等待,因爲線程退出後,不會自動地回收資源,會造成資源泄露

pthread_join()

//功能:等待線程結束
//原型:
int pthread_join(pthread_t thread, void** value_ptr);
//參數:
thread:線程ID
value_ptr:指向一個指向被連接線程的返回碼的指針的指針
//返回值:成功返回0, 失敗返回錯誤碼。

調用該函數的線程將掛起等待,直到id爲thread的線程終止。thread線程以不同的方法終止,通過pthread_join得到的終止狀態是不同的,總結如下:

  1. 如果thread線程通過return返回,value_ptr所指向的單元裏存放的是thread線程函數的返回值。
  2. 如果thread線程被別的線程調用pthread_cancel異常終止掉,value_ptr所指向的單元裏存放的是常熟PTHREAD_CANCELED。
  3. 如果thread線程是自己調用pthread_exit()終止的,value_ptr所指向的單元存放的是傳給pthread_exit()的參數。
  4. 如果對thread線程的終止狀態不感興趣,可以傳NULL給value_ptr參數。

2.4 線程分離
爲什麼要進行線程分離呢?(通俗點來說,“對誰不關心,就去分離誰,不去等待誰”)。 即:
分離一個線程,將線程的joinable屬性修改爲detach屬性,處於此屬性的線程,退出後將自動回收資源。此屬性的線程,不能被等待,否則就會報錯。

  1. 默認情況下,新創建的線程是joinable的,線程退出後,需要對其進行pthread_join操作,否則無法釋放資源,從而造成資源泄露;
  2. 如果不關心線程的返回值,join是一種負擔,這個時候,我們可以告訴系統,當線程退出時,自動釋放線程資源。
//線程組內其他線程對目標線程進行分離
int pthread_detach(pthread_t thread);


//也可以是線程自己分離自己
int pthread_detach(pthread_self());
//pthread_self()函數獲得線程自身的ID
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章