在Linux中使用執行緒

2021-07-10 21:13:05 字數 4072 閱讀 4591

**:

我並不假定你會使用linux的執行緒,所以在這裡就簡單的介紹一下。如果你之前有過多執行緒方面的程式設計經驗,完全可以忽略本文的內容,因為它非常的初級。

首先說明一下,在linux編寫多執行緒程式需要包含標頭檔案pthread.h。也就是說你在任何採用多執行緒設計的程式中都會看到類似這樣的**:

1 #include

當然,進包含乙個標頭檔案是不能搞定執行緒的,還需要連線libpthread.so這個庫,因此在程式連線階段應該有類似這樣的指令:

gcc program.o -o program -lpthread

1. 第乙個例子

在linux下建立的執行緒的api介面是pthread_create(),它的完整定義是:

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

**1第乙個多執行緒程式設計例子

將這段**儲存為thread.c檔案,可以執行下面的命令來生成可執行檔案:

$ gcc thread.c -o thread -lpthread

這段**的執行結果可能是這樣:

$ ./thread

this is the main process.

this is a thread and arg = 10.

thread_ret = 0.

注意,我說的是可能有這樣的結果,在不同的環境下可能會有出入。因為這是多執行緒程式,執行緒**可能先於第24行**被執行。

我們回過頭來再分析一下這段**。在第18行呼叫pthread_create()介面建立了乙個新的執行緒,這個執行緒的入口函式是start_thread(),並且給這個入口函式傳遞了乙個引數,且引數值為10。這個新建立的執行緒要執行的任務非常簡單,只是將顯示「this is a thread and arg = 10」這個字串,因為arg這個引數值已經定義好了,就是10。之後執行緒將arg引數的值修改為0,並將它作為執行緒的返回值返回給系統。與此同時,主程序做的事情就是繼續判斷這個執行緒是否建立成功了。在我們的例子中基本上沒有建立失敗的可能。主程序會繼續輸出「this is the main process」字串,然後呼叫pthread_join()介面與剛才的建立進行合併。這個介面的第乙個引數就是新建立執行緒的控制代碼了,而第二個引數就會去接受執行緒的返回值。pthread_join()介面會阻塞主程序的執行,直到合併的執行緒執行結束。由於執行緒在結束之後會將0返回給系統,那麼pthread_join()獲得的執行緒返回值自然也就是0。輸出結果「thread_ret = 0」也證實了這一點。

那麼現在有乙個問題,那就是pthread_join()介面幹了什麼?什麼是執行緒合併呢?

2. 執行緒的合併與分離

我們首先要明確的乙個問題就是什麼是執行緒的合併。從前面的敘述中讀者們已經了解到了,pthread_create()介面負責建立了乙個執行緒。那麼執行緒也屬於系統的資源,這跟記憶體沒什麼兩樣,而且執行緒本身也要佔據一定的記憶體空間。眾所周知的乙個問題就是c或c++程式設計中如果要通過malloc()或new分配了一塊記憶體,就必須使用free()或delete來**這塊記憶體,否則就會產生著名的記憶體洩漏問題。既然執行緒和記憶體沒什麼兩樣,那麼有建立就必須得有**,否則就會產生另外乙個著名的資源洩漏問題,這同樣也是乙個嚴重的問題。那麼執行緒的合併就是**執行緒資源了。

執行緒的合併是一種主動**執行緒資源的方案。當乙個程序或執行緒呼叫了針對其它執行緒的pthread_join()介面,就是執行緒合併了。這個介面會阻塞呼叫程序或執行緒,直到被合併的執行緒結束為止。當被合併執行緒結束,pthread_join()介面就會**這個執行緒的資源,並將這個執行緒的返回值返回給合併者。

與執行緒合併相對應的另外一種執行緒資源**機制是執行緒分離,呼叫介面是pthread_detach()。執行緒分離是將執行緒資源的**工作交由系統自動來完成,也就是說當被分離的執行緒結束之後,系統會自動**它的資源。因為執行緒分離是啟動系統的自動**機制,那麼程式也就無法獲得被分離執行緒的返回值,這就使得pthread_detach()介面只要擁有乙個引數就行了,那就是被分離執行緒控制代碼。

執行緒合併和執行緒分離都是用於**執行緒資源的,可以根據不同的業務場景酌情使用。不管有什麼理由,你都必須選擇其中一種,否則就會引發資源洩漏的問題,這個問題與記憶體洩漏同樣可怕。

3. 執行緒的屬性

前面還說到過執行緒是有屬性的,這個屬性由乙個執行緒屬性物件來描述。執行緒屬性物件由pthread_attr_init()介面初始化,並由pthread_attr_destory()來銷毀,它們的完整定義是: 

int pthread_attr_init(pthread_attr_t *attr); 

int pthread_attr_destory(pthread_attr_t *attr);

那麼執行緒擁有哪些屬性呢?一般地,linux下的執行緒有:繫結屬性、分離屬性、排程屬性、堆疊大小屬性和滿佔警戒區大小屬性。下面我們就分別來介紹這些屬性。

3.1 繫結屬性

說到這個繫結屬性,就不得不提起另外乙個概念:輕程序(light weight process,簡稱lwp)。輕程序和linux系統的核心執行緒擁有相同的概念,屬於核心的排程實體。乙個輕程序可以控制乙個或多個執行緒。預設情況下,對於乙個擁有n個執行緒的程式,啟動多少輕程序,由哪些輕程序來控制哪些執行緒由作業系統來控制,這種狀態被稱為非繫結的。那麼繫結的含義就很好理解了,只要指定了某個執行緒「綁」在某個輕程序上,就可以稱之為繫結的了。被繫結的執行緒具有較高的相應速度,因為作業系統的排程主體是輕程序,繫結執行緒可以保證在需要的時候它總有乙個輕程序可用。繫結屬性就是幹這個用的。

設定繫結屬性的介面是pthread_attr_setscope(),它的完整定義是:

int pthread_attr_setscope(pthread_attr_t *attr, int scope);

它有兩個引數,第乙個就是執行緒屬性物件的指標,第二個就是繫結型別,擁有兩個取值:pthread_scope_system(繫結的)和pthread_scope_process(非繫結的)。**2演示了這個屬性的使用。

#include

#include

…… int main( int argc, char *argv ) 

**2設定執行緒繫結屬性

不知道你是否在這裡發現了本文的矛盾之處。就是這個繫結屬性跟我們之前說的nptl有矛盾之處。在介紹nptl的時候就說過業界有一種m:n的執行緒方案,就跟這個繫結屬性有關。但是筆者還說過nptl因為linux的「蠢」沒有採取這種方案,而是採用了「1:1」的方案。這也就是說,linux的執行緒永遠都是繫結。對,linux的執行緒永遠都是繫結的,所以pthread_scope_process在linux中不管用,而且會返回enotsup錯誤。

既然linux並不支援執行緒的非繫結,為什麼還要提供這個介面呢?答案就是相容!因為linux的ntpl是號稱posix標準相容的,而繫結屬性正是posix標準所要求的,所以提供了這個介面。如果讀者們只是在linux下編寫多執行緒程式,可以完全忽略這個屬性。如果哪天你遇到了支援這種特性的系統,別忘了我曾經跟你說起過這玩意兒:)

3.2 分離屬性

前面說過執行緒能夠被合併和分離,分離屬性就是讓執行緒在建立之前就決定它應該是分離的。如果設定了這個屬性,就沒有必要呼叫pthread_join()或pthread_detach()來**執行緒資源了。

設定分離屬性的介面是pthread_attr_setdetachstate(),它的完整定義是:

pthread_attr_setdetachstat(pthread_attr_t *attr, int detachstate);

它的第二個引數有兩個取值:pthread_create_detached(分離的)和pthread_create_joinable(可合併的,也是預設屬性)。**3演示了這個屬性的使用。

#include

#include

…… int main( int argc, char *argv ) 

**3設定執行緒分離屬性

linux多工程式設計 

linux的多工程式設計-執行緒池 

對linux中多執行緒程式設計中pthread_join的理解 

linux多執行緒程式設計時如何檢視乙個程序中的某個執行緒是否存活 

有關linux下執行緒的建立 

linux核心執行緒死鎖或死迴圈之後如何讓系統宕機重啟 

linux下c語言實現多執行緒檔案複製 

在新執行緒中使用NSTimer

方法一 void viewdidload void call1 void call2 方法二 void bool animated void timerstart void bool animated 方法三 timer nstimer timerwithtimeinterval 5.0 targe...

在多執行緒中使用 IHTMLDocument2 指標

問題 在多執行緒中使用ihtmldocument2 指標會出現錯誤 解決 使用列集,散集來傳遞ihtmldocument2 指標。宣告全域性變數istream pstream 1 將phtmldocument指標傳遞給pstream。comarshalinterthreadinte ceinstre...

在swift中使用執行緒休眠

c 和php都有sleep讓執行緒休眠指定時間後再繼續執行後面的 swift中應該如何呢?首先,找一下objective c版本是怎麼做的 self performselector selector didtimeout withobject nil afterdelay 60 順便演示下取消 ns...