日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux线程详解

發(fā)布時(shí)間:2023/12/31 linux 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux线程详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

并行和并發(fā)的區(qū)別

1. 并發(fā)(concurrency):在操作系統(tǒng)中,是指一個(gè)時(shí)間段中有幾個(gè)程序都處于已啟動(dòng)運(yùn)行到運(yùn)行完畢之間,且這幾個(gè)程序都是在同一個(gè)處理機(jī)上運(yùn)行。其中兩種并發(fā)關(guān)系分別是同步互斥。(并發(fā)是指同一時(shí)刻只能有一條指令執(zhí)行,但多個(gè)進(jìn)程指令被快速輪換執(zhí)行,使得在宏觀上有多個(gè)進(jìn)程被同時(shí)執(zhí)行的效果--宏觀上并行,針對(duì)單核處理器)

  • 互斥:進(jìn)程間相互排斥的使用臨界資源的現(xiàn)象,就叫互斥。
  • 同步(synchronous):進(jìn)程之間的關(guān)系不是相互排斥臨界資源的關(guān)系,而是相互依賴的關(guān)系。進(jìn)一步的說明:就是前一個(gè)進(jìn)程的輸出作為后一個(gè)進(jìn)程的輸入,當(dāng)?shù)谝粋€(gè)進(jìn)程沒有輸出時(shí)第二個(gè)進(jìn)程必須等待。具有同步關(guān)系的一組并發(fā)進(jìn)程相互發(fā)送的信息稱為消息或事件。(彼此有依賴關(guān)系的調(diào)用不應(yīng)該同時(shí)發(fā)生,而同步就是阻止那些“同時(shí)發(fā)生”的事情
  • 其中并發(fā)又有偽并發(fā)和真并發(fā),偽并發(fā)是指單核處理器的并發(fā),真并發(fā)是指多核處理器的并發(fā)。

2.并行(parallelism):在單處理器中多道程序設(shè)計(jì)系統(tǒng)中,進(jìn)程被交替執(zhí)行,表現(xiàn)出一種并發(fā)的外部特種;在多處理器系統(tǒng)中,進(jìn)程不僅可以交替執(zhí)行,而且可以重疊執(zhí)行。在多處理器上的程序才可實(shí)現(xiàn)并行處理。從而可知,并行是針對(duì)多處理器而言的。并行是同時(shí)發(fā)生的多個(gè)并發(fā)事件,具有并發(fā)的含義,但并發(fā)不一定并行,也亦是說并發(fā)事件之間不一定要同一時(shí)刻發(fā)生。(同一時(shí)刻,有多條指令在多個(gè)處理器上同時(shí)執(zhí)行--針對(duì)多核處理器

同步和異步的區(qū)別

  • 同步(synchronous):進(jìn)程之間的關(guān)系不是相互排斥臨界資源的關(guān)系,而是相互依賴的關(guān)系。進(jìn)一步的說明:就是前一個(gè)進(jìn)程的輸出作為后一個(gè)進(jìn)程的輸入,當(dāng)?shù)谝粋€(gè)進(jìn)程沒有輸出時(shí)第二個(gè)進(jìn)程必須等待。具有同步關(guān)系的一組并發(fā)進(jìn)程相互發(fā)送的信息稱為消息或事件。
  • 異步(asynchronous):異步和同步是相對(duì)的,同步就是順序執(zhí)行,執(zhí)行完一個(gè)再執(zhí)行下一個(gè),需要等待、協(xié)調(diào)運(yùn)行。異步就是彼此獨(dú)立,在等待某事件的過程中繼續(xù)做自己的事,不需要等待這一事件完成后再工作。線程就是實(shí)現(xiàn)異步的一個(gè)方式。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成,從而可以讓主線程干其它的事情。

線程概念

什么是線程

  • LWP:light weight process 輕量級(jí)的進(jìn)程,本質(zhì)仍是進(jìn)程(在Linux環(huán)境下)
  • 進(jìn)程:獨(dú)立地址空間,擁有PCB
  • 線程:也有PCB,但沒有獨(dú)立的地址空間(共享)
  • 區(qū)別:在于是否共享地址空間。 獨(dú)居(進(jìn)程);合租(線程)。
  • Linux下: 線程:最小的執(zhí)行單位,調(diào)度的基本單位。
  • 進(jìn)程:最小分配資源單位,可看成是只有一個(gè)線程的進(jìn)程

Linux內(nèi)核線程實(shí)現(xiàn)原理

類Unix系統(tǒng)中,早期是沒有“線程”概念的,80年代才引入,借助進(jìn)程機(jī)制實(shí)現(xiàn)出了線程的概念。因此在這類系統(tǒng)中,進(jìn)程和線程關(guān)系密切。

  • 輕量級(jí)進(jìn)程(light-weight process),也有PCB,創(chuàng)建線程使用的底層函數(shù)和進(jìn)程一樣,都是clone。
  • 從內(nèi)核里看進(jìn)程和線程是一樣的,都有各自不同的PCB,但是PCB中指向內(nèi)存資源的三級(jí)頁表是相同的。
  • 進(jìn)程可以蛻變成線程
  • 線程可看做寄存器和棧的集合
  • 在linux下,線程最是小的執(zhí)行單位;進(jìn)程是最小的分配資源單位
  • 察看LWP號(hào):ps?–Lf pid 查看指定線程的lwp號(hào)。

三級(jí)映射:進(jìn)程PCB --> 頁目錄(可看成數(shù)組,首地址位于PCB中) --> 頁表 --> 物理頁面 --> 內(nèi)存單元--參考:《Linux內(nèi)核源代碼情景分析》 ----毛德操

  • 對(duì)于進(jìn)程來說,相同的地址(同一個(gè)虛擬地址)在不同的進(jìn)程中,反復(fù)使用而不沖突。原因是他們雖虛擬址一樣,但,頁目錄、頁表、物理頁面各不相同。相同的虛擬址,映射到不同的物理頁面內(nèi)存單元,最終訪問不同的物理頁面。
  • 但!線程不同!兩個(gè)線程具有各自獨(dú)立的PCB,但共享同一個(gè)頁目錄,也就共享同一個(gè)頁表和物理頁面。所以兩個(gè)PCB共享一個(gè)地址空間。
  • 實(shí)際上,無論是創(chuàng)建進(jìn)程的fork,還是創(chuàng)建線程的pthread_create,底層實(shí)現(xiàn)都是調(diào)用同一個(gè)內(nèi)核函數(shù)clone。
  • 如果復(fù)制對(duì)方的地址空間,那么就產(chǎn)出一個(gè)“進(jìn)程”;如果共享對(duì)方的地址空間,就產(chǎn)生一個(gè)“線程”。
  • 因此:Linux內(nèi)核是不區(qū)分進(jìn)程和線程的。只在用戶層面上進(jìn)行區(qū)分。所以,線程所有操作函數(shù) pthread_* 是庫(kù)函數(shù),而非系統(tǒng)調(diào)用。

線程共享資源

  • 1.文件描述符表
  • 2.每種信號(hào)的處理方式
  • 3.當(dāng)前工作目錄
  • 4.用戶ID和組ID
  • 5.內(nèi)存地址空間 (.text/.data/.bss/heap/共享庫(kù))

線程非共享資源

  • 1.線程id
  • 2.處理器現(xiàn)場(chǎng)和棧指針(內(nèi)核棧)
  • 3.獨(dú)立的棧空間(用戶空間棧)
  • 4.errno變量
  • 5.信號(hào)屏蔽字
  • 6.調(diào)度優(yōu)先級(jí)

線程優(yōu)、缺點(diǎn)

  • 優(yōu)點(diǎn): 1. 提高程序并發(fā)性 2. 開銷小 3. 數(shù)據(jù)通信、共享數(shù)據(jù)方便
  • 缺點(diǎn): 1. 庫(kù)函數(shù),不穩(wěn)定 2. 調(diào)試、編寫困難、gdb不支持 3. 對(duì)信號(hào)支持不好
  • 優(yōu)點(diǎn)相對(duì)突出,缺點(diǎn)均不是硬傷。Linux下由于實(shí)現(xiàn)方法導(dǎo)致進(jìn)程、線程差別不是很大

線程控制原語

pthread_self函數(shù)? 獲取線程ID。其作用對(duì)應(yīng)進(jìn)程中 getpid() 函數(shù)。

  • pthread_t pthread_self(void); 返回值:成功:0; 失敗:無!
  • 線程ID:pthread_t類型,本質(zhì):在Linux下為無符號(hào)整數(shù)(%lu),其他系統(tǒng)中可能是結(jié)構(gòu)體實(shí)現(xiàn)
  • 線程ID是進(jìn)程內(nèi)部,識(shí)別標(biāo)志。(兩個(gè)進(jìn)程間,線程ID允許相同)
  • 注意:不應(yīng)使用全局變量 pthread_t tid,在子線程中通過pthread_create傳出參數(shù)來獲取線程ID,而應(yīng)使用pthread_self。

pthread_create函數(shù)? 創(chuàng)建一個(gè)新線程。 其作用,對(duì)應(yīng)進(jìn)程中fork() 函數(shù)。

  • int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
  • 返回值:成功:0; 失敗:錯(cuò)誤號(hào) -----Linux環(huán)境下,所有線程特點(diǎn),失敗均直接返回錯(cuò)誤號(hào)。

參數(shù):

  • pthread_t:當(dāng)前Linux中可理解為:typedef ?unsigned long int ?pthread_t;
  • 參數(shù)1:傳出參數(shù),保存系統(tǒng)為我們分配好的線程ID
  • 參數(shù)2:通常傳NULL,表示使用線程默認(rèn)屬性。若想使用具體屬性也可以修改該參數(shù)。
  • 參數(shù)3:函數(shù)指針,指向線程主函數(shù)(線程體),該函數(shù)運(yùn)行結(jié)束,則線程結(jié)束。
  • 參數(shù)4:線程主函數(shù)執(zhí)行期間所使用的參數(shù),如要傳多個(gè)參數(shù), 可以用結(jié)構(gòu)封裝。
#include <stdio.h> #include <pthread.h> #include <unistd.h>void *fun(void *arg) {printf("I'm thread, Thread ID = %lu\n", pthread_self());return NULL; }int main(void) {pthread_t tid;pthread_create(&tid, NULL, fun, NULL);sleep(1); // 在多線程環(huán)境中,父線程終止,全部子線程被迫終止printf("I am main, my pid = %d\n", getpid());return 0; }

運(yùn)行結(jié)果

  • 在一個(gè)線程中調(diào)用pthread_create()創(chuàng)建新的線程后,當(dāng)前線程從pthread_create()返回繼續(xù)往下執(zhí)行,而新的線程所執(zhí)行的代碼由我們傳給pthread_create的函數(shù)指針start_routine決定。start_routine函數(shù)接收一個(gè)參數(shù),是通過pthread_create的arg參數(shù)傳遞給它的,該參數(shù)的類型為void *,這個(gè)指針按什么類型解釋由調(diào)用者自己定義。start_routine的返回值類型也是void *,這個(gè)指針的含義同樣由調(diào)用者自己定義。start_routine返回時(shí),這個(gè)線程就退出了,其它線程可以調(diào)用pthread_join得到start_routine的返回值,類似于父進(jìn)程調(diào)用wait(2)得到子進(jìn)程的退出狀態(tài),稍后詳細(xì)介紹pthread_join。
  • pthread_create成功返回后,新創(chuàng)建的線程的id被填寫到thread參數(shù)所指向的內(nèi)存單元。我們知道進(jìn)程id的類型是pid_t,每個(gè)進(jìn)程的id在整個(gè)系統(tǒng)中是唯一的,調(diào)用getpid(2)可以獲得當(dāng)前進(jìn)程的id,是一個(gè)正整數(shù)值。線程id的類型是thread_t,它只在當(dāng)前進(jìn)程中保證是唯一的,在不同的系統(tǒng)中thread_t這個(gè)類型有不同的實(shí)現(xiàn),它可能是一個(gè)整數(shù)值,也可能是一個(gè)結(jié)構(gòu)體,也可能是一個(gè)地址,所以不能簡(jiǎn)單地當(dāng)成整數(shù)用printf打印,調(diào)用pthread_self(3)可以獲得當(dāng)前線程的id。

練習(xí):循環(huán)創(chuàng)建多個(gè)線程,每個(gè)線程打印自己是第幾個(gè)被創(chuàng)建的線程。(類似于進(jìn)程循環(huán)創(chuàng)建子進(jìn)程)

#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h>void *tfn(void *arg) {int i;i = (int)arg;//i = *((int *)arg);sleep(i); //通過i來區(qū)別每個(gè)線程printf("I'm %dth thread, Thread_ID = %lu\n", i+1, pthread_self());return NULL; }int main(int argc, char *argv[]) {int n, i;pthread_t tid;if (argc == 2)n = atoi(argv[1]);for (i = 0; i < n; i++) {pthread_create(&tid, NULL, tfn, (void *)i); //將i轉(zhuǎn)換為指針,在tfn中再?gòu)?qiáng)轉(zhuǎn)回整形。}sleep(n);printf("I am main, and I am not a process, I'm a thread!\n" "main_thread_ID = %lu\n", pthread_self());return 0; }

運(yùn)行結(jié)果

線程與共享? 線程間共享全局變量

  • 【牢記】:線程默認(rèn)共享數(shù)據(jù)段、代碼段等地址空間,常用的是全局變量。而進(jìn)程不共享全局變量,只能借助mmap

設(shè)計(jì)程序,驗(yàn)證線程之間共享全局?jǐn)?shù)據(jù)。

#include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h>int var = 100;void *tfn(void *arg) {var = 200;printf("thread\n");return NULL; }int main(void) {printf("At first var = %d\n", var);pthread_t tid;pthread_create(&tid, NULL, tfn, NULL);sleep(1);printf("after pthread_create, var = %d\n", var);return 0; }

運(yùn)行結(jié)果

pthread_exit函數(shù)? 將單個(gè)線程退出

  • void pthread_exit(void *retval); 參數(shù):retval表示線程退出狀態(tài),通常傳NULL
#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h>void *tfn(void *arg) {int i;i = (int)arg; //強(qiáng)轉(zhuǎn)。if (i == 2)pthread_exit(NULL);sleep(i); //通過i來區(qū)別每個(gè)線程printf("I'm %dth thread, Thread_ID = %lu\n", i+1, pthread_self());return NULL; }int main(int argc, char *argv[]) {int n , i;pthread_t tid;if (argc == 2)n = atoi(argv[1]);for (i = 0; i < n; i++){pthread_create(&tid, NULL, tfn, (void *)i); //將i轉(zhuǎn)換為指針,在tfn中再?gòu)?qiáng)轉(zhuǎn)回整形。}sleep(n);printf("I am main, I'm a thread!\n" "main_thread_ID = %lu\n", pthread_self());return 0; }

運(yùn)行結(jié)果

思考:使用exit將指定線程退出,可以嗎??結(jié)論:線程中,禁止使用exit函數(shù),會(huì)導(dǎo)致進(jìn)程內(nèi)所有線程全部退出。

  • 在不添加sleep控制輸出順序的情況下。pthread_create在循環(huán)中,幾乎瞬間創(chuàng)建5個(gè)線程,但只有第1個(gè)線程有機(jī)會(huì)輸出(或者第2個(gè)也有,也可能沒有,取決于內(nèi)核調(diào)度)如果第3個(gè)線程執(zhí)行了exit,將整個(gè)進(jìn)程退出了,所以全部線程退出了。
  • 所以,多線程環(huán)境中,應(yīng)盡量少用,或者不使用exit函數(shù),取而代之使用pthread_exit函數(shù),將單個(gè)線程退出。任何線程里exit導(dǎo)致進(jìn)程退出,其他線程未工作結(jié)束,主控線程退出時(shí)不能return或exit。
  • 另注意,pthread_exit或者return返回的指針?biāo)赶虻膬?nèi)存單元必須是全局的或者是用malloc分配的,不能在線程函數(shù)的棧上分配,因?yàn)楫?dāng)其它線程得到這個(gè)返回指針時(shí)線程函數(shù)已經(jīng)退出了。

pthread_join函數(shù)? 阻塞等待線程退出,獲取線程退出狀態(tài) 其作用,對(duì)應(yīng)進(jìn)程中 waitpid() 函數(shù)。

  • int pthread_join(pthread_t thread, void **retval); 成功:0;失敗:錯(cuò)誤號(hào)
  • 參數(shù):thread:線程ID (【注意】:不是指針);retval:存儲(chǔ)線程結(jié)束狀態(tài)。
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h>typedef struct {int a;int b; } exit_t;void *tfn(void *arg) {exit_t *ret;ret = malloc(sizeof(exit_t)); // malloc分配ret->a = 100;ret->b = 300;sleep(3);//pthread_exit((void *)ret);return (void *)ret; }int main(void) {pthread_t tid;exit_t *retval;pthread_create(&tid, NULL, tfn, NULL);/*調(diào)用pthread_join可以獲取線程的退出狀態(tài)*/pthread_join(tid, (void **)&retval); //wait(&status);printf("a = %d, b = %d \n", retval->a, retval->b);return 0; }

對(duì)比記憶:

  • 進(jìn)程中:main返回值、exit參數(shù)-->int;等待子進(jìn)程結(jié)束 wait 函數(shù)參數(shù)-->int *
  • 線程中:線程主函數(shù)返回值、pthread_exit-->void *;等待線程結(jié)束 pthread_join 函數(shù)參數(shù)-->void **
  • 參數(shù) retval 非空用法

    調(diào)用該函數(shù)的線程將掛起等待,直到id為thread的線程終止。thread線程以不同的方法終止,通過pthread_join得到的終止?fàn)顟B(tài)是不同的,總結(jié)如下:

  • 如果thread線程通過return返回,retval所指向的單元里存放的是thread線程函數(shù)的返回值。
  • 如果thread線程被別的線程調(diào)用pthread_cancel異常終止掉,retval所指向的單元里存放的是常數(shù)PTHREAD_CANCELED。
  • 如果thread線程是自己調(diào)用pthread_exit終止的,retval所指向的單元存放的是傳給pthread_exit的參數(shù)。
  • 如果對(duì)thread線程的終止?fàn)顟B(tài)不感興趣,可以傳NULL給retval參數(shù)。
  • 練習(xí):使用pthread_join函數(shù)將循環(huán)創(chuàng)建的多個(gè)子線程回收。

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h>int var = 100;void *tfn(void *arg) {int i;i = (int)arg;sleep(i);if (i == 1) {var = 333;printf("var = %d\n", var);return (void *)var;}else if (i == 3) {var = 777;printf("I'm %dth pthread, pthread_id = %lu\n var = %d\n", i+1, pthread_self(), var);pthread_exit((void *)var);} else {printf("I'm %dth pthread, pthread_id = %lu\n var = %d\n", i+1, pthread_self(), var);pthread_exit((void *)var);}return NULL; }int main(void) {pthread_t tid[5];int i;int *ret[5]; for (i = 0; i < 5; i++)pthread_create(&tid[i], NULL, tfn, (void *)i);for (i = 0; i < 5; i++) {pthread_join(tid[i], (void **)&ret[i]);printf("-------%d 's ret = %d\n", i, (int)ret[i]);}printf("I'm main pthread tid = %lu\t var = %d\n", pthread_self(), var);sleep(i);return 0; }

    運(yùn)行結(jié)果

    pthread_cancel函數(shù)? 殺死(取消)線程 其作用,對(duì)應(yīng)進(jìn)程中 kill() 函數(shù)。

    • int pthread_cancel(pthread_t thread); 成功:0;失敗:錯(cuò)誤號(hào)
    #include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h>void *tfn1(void *arg) {printf("thread 1 returning\n");return (void *)111; }void *tfn2(void *arg) {printf("thread 2 exiting\n");pthread_exit((void *)222); }void *tfn3(void *arg) {while (1) {printf("thread 3: I'm going to die in 3 seconds ...\n");sleep(1);pthread_testcancel(); //自己添加取消點(diǎn)*/}return (void *)666; }int main(void) {pthread_t tid;void *tret = NULL;pthread_create(&tid, NULL, tfn1, NULL);pthread_join(tid, &tret);printf("thread 1 exit code = %d\n\n", (int)tret);pthread_create(&tid, NULL, tfn2, NULL); pthread_join(tid, &tret);printf("thread 2 exit code = %d\n\n", (int)tret);pthread_create(&tid, NULL, tfn3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid, &tret);printf("thread 3 exit code = %d\n", (int)tret);return 0; }

    運(yùn)行結(jié)果

    • 線程的取消并不是實(shí)時(shí)的,而有一定的延時(shí)。需要等待線程到達(dá)某個(gè)取消點(diǎn)(檢查點(diǎn))。
    • 類似于玩游戲存檔,必須到達(dá)指定的場(chǎng)所(存檔點(diǎn),如:客棧、倉(cāng)庫(kù)、城里等)才能存儲(chǔ)進(jìn)度。殺死線程也不是立刻就能完成,必須要到達(dá)取消點(diǎn)。
    • 取消點(diǎn):是線程檢查是否被取消,并按請(qǐng)求進(jìn)行動(dòng)作的一個(gè)位置。通常是一些系統(tǒng)調(diào)用creat,open,pause,close,read,write.....?執(zhí)行命令man?7 pthreads可以查看具備這些取消點(diǎn)的系統(tǒng)調(diào)用列表。也可參閱 APUE.12.7 取消選項(xiàng)小節(jié)。
    • 可粗略認(rèn)為一個(gè)系統(tǒng)調(diào)用(進(jìn)入內(nèi)核)即為一個(gè)取消點(diǎn)。如線程中沒有取消點(diǎn),可以通過調(diào)用pthreestcancel函數(shù)自行設(shè)置一個(gè)取消點(diǎn)。
    • 被取消的線程, 退出值定義在Linux的pthread庫(kù)中。常數(shù)PTHREAD_CANCELED的值是-1。可在頭文件pthread.h中找到它的定義:#define PTHREAD_CANCELED ((void *) -1)因此當(dāng)我們對(duì)一個(gè)已經(jīng)被取消的線程使用pthread_join回收時(shí),得到的返回值為-1。

    pthread_detach函數(shù)? 實(shí)現(xiàn)線程分離

    • int pthread_detach(pthread_t thread); 成功:0;失敗:錯(cuò)誤號(hào)
    • 線程分離狀態(tài):指定該狀態(tài),線程主動(dòng)與主控線程斷開關(guān)系。線程結(jié)束后,其退出狀態(tài)不由其他線程獲取,而直接自己自動(dòng)釋放。網(wǎng)絡(luò)、多線程服務(wù)器常用。
    • 在線程被分離后,不能使用pthread_join等待它的終止?fàn)顟B(tài)。
    • 進(jìn)程若有該機(jī)制,將不會(huì)產(chǎn)生僵尸進(jìn)程。僵尸進(jìn)程的產(chǎn)生主要由于進(jìn)程死后,大部分資源被釋放,一點(diǎn)殘留資源仍存于系統(tǒng)中,導(dǎo)致內(nèi)核認(rèn)為該進(jìn)程仍存在。
    • 也可使用 pthread_create函數(shù)參2(線程屬性)來設(shè)置線程分離。

    使用pthread_detach函數(shù)實(shí)現(xiàn)線程分離?

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <pthread.h>void *tfn(void *arg) {int n = 3;while (n--) {printf("thread count %d\n", n);sleep(1); }return (void *)1;//pthread_exit((void *)1); }int main(void) {pthread_t tid;void *tret;int err;#if 1pthread_attr_t attr; /*通過線程屬性來設(shè)置游離態(tài)*/pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);pthread_create(&tid, &attr, tfn, NULL);#elsepthread_create(&tid, NULL, tfn, NULL);pthread_detach(tid); //讓線程分離 ----自動(dòng)退出,無系統(tǒng)殘留資源#endifwhile (1) {err = pthread_join(tid, &tret);printf("thread exit code = %d\n", (int)tret);printf("-------------err= %d\n", err);if (err != 0)fprintf(stderr, "thread_join error: %s\n\n", strerror(err));elsefprintf(stderr, "thread exit code %d\n\n", (int)tret);sleep(1);}return 0; }

    運(yùn)行結(jié)果

    • 一般情況下,線程終止后,其終止?fàn)顟B(tài)一直保留到其它線程調(diào)用pthread_join獲取它的狀態(tài)為止。但是線程也可以被置為detach狀態(tài),這樣的線程一旦終止就立刻回收它占用的所有資源,而不保留終止?fàn)顟B(tài)。不能對(duì)一個(gè)已經(jīng)處于detach狀態(tài)的線程調(diào)用pthread_join,這樣的調(diào)用將返回EINVAL錯(cuò)誤。也就是說,如果已經(jīng)對(duì)一個(gè)線程調(diào)用了pthread_detach就不能再調(diào)用pthread_join了。

    終止線程方式

    總結(jié):終止某個(gè)線程而不終止整個(gè)進(jìn)程,有三種方法:

  • 從線程主函數(shù)return。這種方法對(duì)主控線程不適用,從main函數(shù)return相當(dāng)于調(diào)用exit。
  • 一個(gè)線程可以調(diào)用pthread_cancel終止同一進(jìn)程中的另一個(gè)線程。
  • 線程可以調(diào)用pthread_exit終止自己。
  • 控制原語對(duì)比

    進(jìn)程? ? ? ? ? ? 線程

    fork? ? ? ? ? ? ?pthread_create

    exit? ? ? ? ? ? ?pthread_exit

    wait? ? ? ? ? ? pthread_join

    kill? ? ? ? ? ? ? pthread_cancel

    getpid? ? ? ? pthread_self 命名空間

    ?

    總結(jié)

    以上是生活随笔為你收集整理的Linux线程详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。