(八)C線程

1.線程爲什麼能彌補進程的缺點

爲什麼線程切換的開銷很低

但是使用多線程來實現多線任務時,由於線程本質上它只是程序(進程)的一個函數,只不過線程函數

與普通函數的區別是,普通函數時單線的運行關係,而線程函數被註冊爲線程後,是多線併發運行。

                 

對於普通函數來說,只有相互調動時纔會涉及函數間的切換,但是對於線程函數來說,只要運行時間片到了就會切換,但是不管是那種函數間的切換,進程自己函數的切換隻是進程內部的事情,不涉及進程間切換, 就省去了進程間切換巨大銷。

 

疑問:線程切換不一樣需要開銷?

剛說過,線程的切換其實就是函數間的切換,函數切換當然也需要開銷,但是這些開銷相比進程間切換的開銷來說,已經非常小了。

 爲什麼線程間數據通信的開銷很低

線程的本質就是函數,請問大家函數之間如果想要數據共享(通信)的話,應該怎麼辦?

函數間通信有兩種方式:

              

是不是有了線程後,進程就不需要了?

線程是不可能完全替代掉進程的,只有在多線任務時會替代進程,但是運行新程序的時,我們還是必須創建子進程。

 

線程的本質是函數,函數運行需要內存空間,這個內存空間怎麼來,事實上線程運行的內存空間就是進程的內存空間,因此線程運行時必須依賴於進程的存在,如果沒有進程所提供的內存空間這個資源,線程根本無法運行。

換句話說,線程作爲函數,只是進程的一個部分而已,線程是不可能脫離進程而獨立存在。

 

對於進程中的所有函數來說(包括線程函數),進程中幾乎所有的資源都是共享的,比如打開的文件描述,所有可以被調用的子函數,進程的當前工作目錄,進程uid、gid,進程PID等等。

 線程自己獨立的屬性

(1)每個線程擁有自己獨立的線程ID(TID)

(2)每個線程有獨立的切換狀態

         

(3)有自己獨立的函數棧

        

(4)自己獨立的錯誤號

       

(5)每一個線程有自己獨立的信號屏蔽字和未決信號集

(6)每個線程有自己獨立的tack_struct結構體

      

什麼時候使用多線程和多進程

線程

        程序涉及多線任務時,使用線程。

進程

      程序涉及到運行新程序時,必須使用多進程,不過一般來說,如果不是大型軟件和框架的話,我們的程序並不需要執行新程序。

2.線程控制相關的函數

線程控制函數有: pthread_create、pthread_join、 pthread_detach、pthread_cancel、pthread_exit等。   

線程函數是由誰提供的

進程控制的fork、exec等函數都是由os系統提供的,那線程函數是由誰提供的呢?

原本線程函數也可以完全由OS來實現,但是後來爲了不給OS增加負擔,同時也爲了提高線程的靈活性,後來的線程就不在由OS提供,而是由單獨的線程庫來提供,不過線程庫在實現時,也是調用了相應的系統API的,也就是說線程的核心實現也是離不開OS支持的。

線程庫

(1)c線程函數

     由c線程庫提供,注意這個c線程庫並不是C標準庫,而是POSIX C庫的一部分

     posix的c線程庫,是由美國一些標準組織制定,並有相應c語言和unix、Linux維護團隊開發的。        、

(2)java、c++、c#的線程函數

    這些語言的線程庫,是由這些語言的維護團隊來開發的。

線程庫和OS系統API的關係

    線程庫函數實際上也是封住OS的相應API來實現的,如果線程庫運行在Linux這邊的話,線程庫其實就是 通過調用Linux的clone()等系統函數實現的。

   將線程函數註冊爲線程時,其實就是通過調用這類系統API,然後去模擬我們的進程來實現的,正是因爲是模擬進程來實現的,所以線程函數才能進程一樣,一起被併發運行。

c線程控制函數

 線程庫和函數手冊的安裝

sudo apt-get install glibc-doc :安裝線程庫
sudo apt-get install manpages-posix-dev:安裝線程庫的函數手冊

pthread_create

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
	void *(*start_routine) (void *), void *arg);

  

需要強調的地方

  

pthread_cancel

#include <pthread.h>

int pthread_cancel(pthread_t thread);

  

pthread_exit

#include <pthread.h>

void pthread_exit(void *retval); 

  

pthread_self

#include <pthread.h>

pthread_t pthread_self(void);

  

pthread_join

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);

  

疑問:線程所用內存資源本身就是來自於進程空間,既然進程結束後,整個進程的資源都會被回收掉,次線程結束時幹嘛要回收資源,等進程結束後一併回收不就得了嗎? 

答:有些程序(進程)一旦運行後將會長期運行,不會結束,所以次線程在結束時必須回收資源,如果不回收,每結束一個次線程就導致一部分資源被佔用,慢慢累積會使得整個進程資源越用越少,最後導致進程崩潰,所以次線程結束時,必須回收次線程資源。

pthread_detach    

#include <pthread.h>

int pthread_detach(pthread_t thread);

  

註冊線程退出處理函數

可以註冊進程退出處理函數,其實也可以註冊線程退出處理函數,線程在退出時會自動調用,實現線程的掃尾處理

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

功能

  

彈棧線程退出處理函數的幾種條件

  

線程的屬性設置

可以設置的線程屬性有,

  1. · 設置綁定屬性
  2. · 設置分離屬性
  3. · 設置線程堆棧屬性
  4. · 設置線程調度優先級屬性   等等

如果我們什麼屬性都不設置,那麼線程使用的就是默認屬性,事實上默認屬性所提供的功能就已經足夠我們使用了

將線程分離有兩種方法:

· 調用pthread_detach函數實現
· 通過設置分離屬性實現

這裏介紹第二種:分離屬性設置的步驟

線程的資源(數據)保護

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章