天天看點

1、Linux多線程,基本概念

說明:以下内容,根據參考中【1~6】内容整理而得。

一、基本概念

1、線程是計算機中獨立運作的最小機關。程序是配置設定資源的機關。

2、為什麼使用多線程?

(1)啟動一個新的程序必須配置設定給它獨立的位址空間,建立衆多的資料表來維護它的代碼段、堆棧段和資料段,這是一種"昂貴"的多任務工作方式。而運作于一個程序中的多個線程,它們彼此之間使用相同的位址空間,共享大部分資料,啟動一個線程所花費的空間遠遠小于啟動一個程序所花費的空間,而且,線程間彼此切換所需的時間也遠遠小于程序間切換所需要的時間。據統計,總的說來,一個程序的開銷大約是一個線程開銷的30倍左右。

(2)使用多線程的理由之二是線程間友善的通信機制。對不同程序來說,它們具有獨立的資料空間,要進行資料的傳遞隻能通過通信的方式進行,這種方式不僅費時,而且很不友善。線程則不然,由于同一程序下的線程之間共享資料空間,是以一個線程的資料可以直接為其它線程所用,這不僅快捷,而且友善。當然,資料的共享也帶來其他一些問題,有的變量不能同時被兩個線程所修改,有的子程式中聲明為static的資料更有可能給多線程程式帶來災難性的打擊,這些正是編寫多線程程式時最需要注意的地方。

此外,多線程程式作為一種多任務、并發的工作方式,當然有以下的優點:

1) 提高應用程式響應。這對圖形界面的程式尤其有意義,當一個操作耗時很長時,整個系統都會等待這個操作,此時程式不會響應鍵盤、滑鼠、菜單的操作,而使用多線程技術,将耗時長的操作(time consuming)置于一個新的線程,可以避免這種尴尬的情況。

2) 使多CPU系統更加有效。作業系統會保證當線程數不大于CPU數目時,不同的線程運作于不同的CPU上。

3) 改善程式結構。一個既長又複雜的程序可以考慮分為多個線程,成為幾個獨立或半獨立的運作部分,這樣的程式會利于了解和修改。

3、線程不像程序那樣,不是按照嚴格的父子層次來組織的。和一個程序相關的線程組成一個對等線程池(a pool of peers)。對等(線程)池概念的主要影響是,一個線程可以殺死它的任何對等線程,或者等待它的任意對等線程終止;進一步來說,每個對等線程都能讀寫相同的共享資料。

4、相關函數

1)建立線程

#include <pthread.h>

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

pthread_t pthread_self(void);

int pthread_equal(pthread_t thread1,pthread_t thread2);

int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));

    linux系統支援POSIX多線程接口,稱為pthread。編寫linux下的多線程程式,需要包含頭檔案pthread.h,連結時需要使用庫libpthread.a。

    如果在主線程裡面建立線程,程式就會在建立線程的地方産生分支,變成兩個部分執行。線程的建立通過函數pthread_create來完成。成功傳回0。

參數:

thread: 參數是一個指針,當線程成功建立時,傳回建立線程ID。

attr: 用于指定線程的屬性

start_routine: 該參數是一個函數指針,指向線程建立後要調用的函數。

arg: 傳遞給線程函數的參數。

2)線程終止

兩種方式終止線程。

第一通過return從線程函數傳回,

第二種通過調用pthread_exit()函數使線程退出。

需要注意的地方:一是,主線程中如果從main函數傳回或是調用了exit函數退出主線程,則整個程序終止,此時所有的其他線程也将終止。另一種是,如果主線程調用pthread_exit函數,則僅僅是主線程消亡,程序不會結束,其他線程也不會結束,知道所有的線程都結束時,程序才結束。

3)線程屬性

/* man pthread_attr_init */

typedef struct

{

  int                  detachstate;    //是否與其他線程脫離同步

  int                  schedpolicy;    //新線程的排程政策

  struct sched_param    schedparam;        //運作優先級等

  int                  inheritsched;    //是否繼承調用者線程的值

  int             scope;       //線程競争CPU的範圍(優先級的範圍)

  size_t             guardsize;        //警戒堆棧的大小

  int                  stackaddr_set;    //堆棧位址集

  void *              stackaddr;        //堆棧位址

  size_t             stacksize;        //堆棧大小

} pthread_attr_t;

    屬性值不能直接設定,須使用相關函數進行操作,初始化的函數為pthread_attr_init,這個函數必須在pthread_create函數之前調用。

(1)關于線程綁定

    關于線程的綁定,牽涉到另外一個概念:輕程序(LWP:Light Weight Process)。輕程序可以了解為核心線程,它位于使用者層和系統層之間。系統對線程資源的配置設定、對線程的控制是通過輕程序來實作的,一個輕程序可以控制一個或多個線程。預設狀況下,啟動多少輕程序、哪些輕程序來控制哪些線程是由系統來控制的,這種狀況即稱為非綁定的。綁定狀況下,則顧名思義,即某個線程固定的"綁"在一個輕程序之上。被綁定的線程具有較高的響應速度,這是因為CPU時間片的排程是面向輕程序的,綁定的線程可以保證在需要的時候它總有一個輕程序可用。通過設定被綁定的輕程序的優先級和排程級可以使得綁定的線程滿足諸如實時反應之類的要求。

    設定線程綁定狀态的函數為pthread_attr_setscope,它有兩個參數,第一個是指向屬性結構的指針,第二個是綁定類型,它有兩個取值:PTHREAD_SCOPE_SYSTEM(綁定的)和PTHREAD_SCOPE_PROCESS(非綁定的)。下面的代碼即建立了一個綁定的線程。

pthread_attr_t attr;

pthread_t tid;

/*初始化屬性值,均設為預設值*/

pthread_attr_init(&attr);

pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

pthread_create(&tid, &attr, (void *) my_function, NULL);