一. 概念
首先Linux並不存在真正的線程,Linux的線程是使用進程類比的。當我們需要在一個進程中同時運行多個執行流時,我們並不可以開闢多個進程執行我們的操作(32位機器裡每個進程認為它 獨享 4G的記憶體資源),此時便引入了線程,例如當我們既需要下載內容,又需要瀏覽網頁時,此時多線程便起了作用。線程是承擔調度的基本單位,一個進程可擁有多個線程,它的執行力度比進程更加細緻,線程資源共用。
二. 特點
由於同一進程的多個線程共用同一地址空間,所以程式碼片段,資料區段是共用的,如果定義一個函數(儲存在程式碼片段),各線程都可以進行調用,如果定義個全域變數(儲存在資料區段),在各線程中都可以訪問到,除此之外,各線程還共用以下進程資源和環境:
1.檔案描述符表
2.每種訊號的處理方式(SIG_IGN,SIG_DFL,使用者自訂)
3.當前工作目錄
4.使用者id和組id
但有些資源是線程獨享的:
1.線程id
2.上下文,包括各種寄存器的值,程式計數器和棧指標
3.棧空間
4.errno變數
5.訊號屏蔽字
6.調度優先順序
三. 線程的簡單實用
1.建立線程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
傳回值:成功返回0,失敗返回錯誤號碼。在一個線程中調pthread_create()建立新的線程後,當前線程從pthread_create()返回繼續往下執行,新的線程所執行的代碼由我們傳給pthread_create的函數指標start_routine決定。
thread參數傳入線程的id,void ( star_routine)(void )由使用者進行撰寫。
2.線程終止
void pthread_exit(void *retval)函數用於進程終止,傳入一個id,調用exit()的話,主進程會終止。終止線程由三種方法:
1).從線程函數return。這種方法法對主線程不適用,從main函數return相當於調用exit。
2).一個線程可以調用pthread_cancel終止同一進程中的另一個線程。
3).線程可以調pthread_exit終自己。
retval是void *類型,其它線程可以調pthread_join獲得這個指標。
3.線程等待
int pthread_join(pthread_t thread,void **retval);成功返回0,失敗返回錯誤號碼。 線程的等待是以阻塞式等待,線程不等待會產生記憶體泄露(類似進程的殭屍進程)
4.進程取消
在合理範圍內,線程可以自我或者被別人取消。取消後返回PTHREAD_CANCELED(它被定義為(void *)-1),取消調用函數pthread_cancel(id);
5.線程分離
在任何一個時間點上線程是可結合的(joinable)或者是分離的(detached)。一個可結合的線程能夠被其他線程收回其資源和殺死。在被其他線程回收之前,它的儲存空間資源(例如棧)是不釋放的。相反一個分離的線程是不能被其他線程回收或殺死的,它的儲存空間資源在它終時時由系統自動釋放。
預設情況一個線程是可結合的,每一個可結合的線程都應該被顯性的回收,既調用pthread_join()函數,分離調用函數pthread_detach。分離的這個函數是非阻塞的,可以立即返回。但為什麼要分離呢。因為主進程在處理線程時,要處理不止一個,而每一個都需要被等待,然而join是阻塞式的,這樣的話就只能處理一個線程,所以要加入分離,這樣就可以處理多個線程。調用pthread_detach()後,這些子進程的狀態會被設定為分離的,該線程運行結束會自動釋放所有資源。
下面為測試代碼:
#include <stdio.h>#include <stdlib.h>#include <pthread.h>void* thread1(){ pthread_detach(pthread_self());//分離後仍可被等待 printf("pid is: %d, tid is: %d\n", getpid(),pthread_self()); return (void*)1;}int main(){ pthread_t tid; void *ret; int err = pthread_create(&tid, NULL, thread1, NULL); if (err != 0) { perror("pthread_create\n"); return err; } //如果直接運行等待代碼,一般會等待成功,返回1 //如果在等待之前加入取消。等待錯誤,返回-1 // pthread_cancel(tid); //線程可以自我取消也可以被取消,線程終止 //調用pthread_exit(tid);和取消同樣用法。 int tmp = pthread_join(tid, &ret); if (tmp == 0) { printf("wait success\n"); } else { printf("wait failed\n"); } printf(" pid is: %d, tid is: %d\n", getpid(),pthread_self()); sleep(1); return 0;}