這篇文章為大家帶來了關於linux中線程的創建與使用相關知識,希望對大家有幫助。
執行緒與進程的差異 (1)進程: 是作業系統調度最小單位。 Linux下可以透過ps、top等指令查看進程的詳細資料。 (2)執行緒: 是進程調度的最小單位,每個行程都有一個主執行緒。在行程裡主要做事情就是執行緒。
(3)在全系統中,進程ID是唯一標識,對於進程的管理都是透過PID來實現的。每建立一個進程,核心去中就會創建一個結構體來儲存該進程的全部訊息,每一個儲存進程資訊的節點也都保存著自己的PID。需要管理該行程時就透過這個ID來實現(例如發送訊號)。當子進程結束要回收時(子進程呼叫exit()退出或程式碼執行完),需要透過wait()系統呼叫來進行,未回收的消亡進程會成為殭屍進程,其進程實體已經不復存在,但會虛佔PID資源,因此回收是必要的。
對於執行緒而言,若要主動終止需要呼叫pthread_exit() ,主執行緒需要呼叫pthread_join()來回收(前提是該執行緒沒有設定 「分離屬性」)。像線發送線程訊號也是透過線程ID實現
進程間的通訊方式: A.共享記憶體B.訊息佇列C.信號量D.有名管道E.無名管道F.訊號G.檔案H. socket 執行緒間的通訊方式: A.互斥量B.自旋鎖C.條件變數D.讀寫鎖E.執行緒訊號F.全域變數
進程間採用的通訊方式要麼需要切換內核上下文,要么要與外設訪問(有名管道,文件)。所以速度會比較慢。而線程採用自己特有的通信方式的話,基本上都在自己的進程空間內完成,不存在切換,所以通信速度會較快。也就是說,進程間與執行緒間分別採用的通訊方式,除了種類的差異外,還有速度上的差異。
說明: 當執行多執行緒的程序捕獲到訊號時,只會阻塞主線程,其他子執行緒不會影響會繼續執行。
2.1 建立執行緒
pthread_create是Unix作業系統(Unix、Linux等)的建立執行緒的函數。編譯時需要指定連結函式庫: -lpthread 函式原型
#include <pthread.h> int pthread_create ( pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg );
參數介紹
第一個參數為指向執行緒標識符的指標。第二個參數用來設定線程屬性。預設可填NULL。第三個參數是執行緒運行函數的起始位址。最後一個參數是運行函數的參數。不需要參數可填NULL。 Linux下查看函數幫助:# man pthread_create
傳回值: 若執行緒建立成功,則傳回0。若執行緒建立失敗,則傳回出錯編號。當執行緒建立成功後, attr參數用於指定各種不同的執行緒屬性。新建立的執行緒從start_rtn函數的位址開始運行,該函數只有一個萬能指標參數arg,如果需要向執行緒工作函數傳遞的參數不只一個,那麼需要把這些參數放到一個結構中,然後把這個結構的位址作為arg的參數傳入。
範例:
#include <stdio.h> #include <pthread.h> //线程函数1 void *pthread_func1(void *arg) { while(1) { printf("线程函数1正在运行.....\n"); sleep(2); } } //线程函数2 void *pthread_func2(void *arg) { while(1) { printf("线程函数2正在运行.....\n"); sleep(2); } } int main(int argc,char **argv) { pthread_t thread_id1; pthread_t thread_id2; /*1. 创建线程1*/ if(pthread_create(&thread_id1,NULL,pthread_func1,NULL)) { printf("线程1创建失败!\n"); return -1; } /*2. 创建线程2*/ if(pthread_create(&thread_id2,NULL,pthread_func2,NULL)) { printf("线程2创建失败!\n"); return -1; } /*3. 等待线程结束,释放线程的资源*/ pthread_join(thread_id1,NULL); pthread_join(thread_id2,NULL); return 0; } //gcc pthread_demo_code.c -lpthread
2.2 退出執行緒
執行緒透過呼叫pthread_exit函數終止執行,就如同進程在結束時呼叫exit函數一樣。這個函數的作用是,終止呼叫它的執行緒並傳回一個指向某個物件的指標。
這個函數的作用是,終止呼叫它的線程並傳回一個指向某個物件的指針,該回傳值可以透過pthread_join函數的第二個參數來得到。
函數原型
#include <pthread.h> void pthread_exit(void *retval);
參數解析 執行緒的需要傳回的位址。注意: 執行緒結束必須釋放執行緒堆疊,就是說執行緒函數必須呼叫pthread_exit()結束,否則直到主行程函數退出才釋放
2.3 等待執行緒結束
# pthread_join()函數,以阻塞的方式等待thread指定的執行緒結束。當函數返回時,被等待線程的資源被收回。如果線程已經結束,那麼函數會立即傳回。且thread指定的執行緒必須是joinable(結合屬性)屬性。函數原型
#include <pthread.h> int pthread_join(pthread_t thread, void **retval);
參數 第一個參數: 執行緒標識符,即執行緒ID,標識唯一執行緒。最後一個參數: 使用者定義的指針,用來儲存被等待線程返回的位址。傳回值 0代表成功。失敗,回傳的則是錯誤號碼。接收執行緒傳回值範例:
//退出线程 pthread_exit ("线程已正常退出"); //接收线程的返回值 void *pth_join_ret1; pthread_join( thread1, &pth_join_ret1);
2.4 執行緒分離屬性
#创建一个线程默认的状态是joinable(结合属性),如果一个线程结束运行但没有调用pthread_join,则它的状态类似于进程中的Zombie Process(僵死进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于进程的wait,waitpid)。但是调用pthread_join(pthread_id)函数后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。
pthread_detach函数可以将该线程的状态设置为detached(分离状态),则该线程运行结束后会自动释放所有资源。 函数原型
#include <pthread.h> int pthread_detach(pthread_t thread);
参数 线程标识符 返回值 0表示成功。错误返回错误码。 EINVAL线程并不是一个可接合线程。 ESRCH没有线程ID可以被发现。
2.5 获取当前线程的标识符
pthread_self函数功能是获得线程自身的ID。 函数原型
#include <pthread.h> pthread_t pthread_self(void);
返回值 当前线程的标识符。 pthread_t的类型为unsigned long int,所以在打印的时候要使用%lu方式,否则显示结果出问题。
2.6 自动清理线程资源
线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序。用于程序异常退出的时候做一些善后的资源清理。 在POSIX线程API中提供了一个pthread_cleanup_push()/pthread_cleanup_pop()函数用于自动释放资源。从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和异常终止)都将执行pthread_cleanup_push()所指定的清理函数。
注意:pthread_cleanup_push函数与pthread_cleanup_pop函数需要成对调用。 函数原型
void pthread_cleanup_push(void (*routine)(void *),void *arg); //注册清理函数 void pthread_cleanup_pop(int execute); //释放清理函数
参数 void (*routine)(void *) :处理程序的函数入口。 void *arg :传递给处理函数的形参。 int execute:执行的状态值。 0表示不调用清理函数。1表示调用清理函数。
导致清理函数调用的条件:
调用pthread_exit()函数
pthread_cleanup_pop的形参为1。 注意:return不会导致清理函数调用。
2.7 自动清理线程示例代码
#include <stdio.h> #include <pthread.h> #include <stdlib.h> //线程清理函数 void routine_func(void *arg) { printf("线程资源清理成功\n"); } //线程工作函数 void *start_routine(void *dev) { pthread_cleanup_push(routine_func,NULL); //终止线程 // pthread_exit(NULL); pthread_cleanup_pop(1); //1会导致清理函数被调用。0不会调用。 } int main(int argc,char *argv[]) { pthread_t thread_id; //存放线程的标识符 /*1. 创建线程*/ if(pthread_create(&thread_id,NULL,start_routine,NULL)!=0) { printf("线程创建失败!\n"); } /*2.设置线程的分离属性*/ if(pthread_detach(thread_id)!=0) { printf("分离属性设置失败!\n"); } while(1){} return 0; }
2.8 线程取消函数
pthread_cancel函数为线程取消函数,用来取消同一进程中的其他线程。
头文件: #include <pthread.h> 函数原型:pthread_cancel(pthread_t tid);
相关推荐:《Linux视频教程》
以上是深入了解Linux系統程式設計-(pthread)執行緒建立與使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!