博客專欄

EEPW首頁 > 博客 > 嵌入式Linux:線程的創(chuàng)建、終止、回收、取消和分離

嵌入式Linux:線程的創(chuàng)建、終止、回收、取消和分離

發(fā)布人:美男子玩編程 時(shí)間:2025-01-21 來源:工程師 發(fā)布文章

線程的創(chuàng)建、終止、取消、回收和分離操作是多線程編程的核心。

在多線程編程中,需要妥善管理線程的生命周期,以避免資源泄漏、競爭條件或僵尸線程等問題。


1

創(chuàng)建線程

在 Linux 中,默認(rèn)情況下,一個(gè)進(jìn)程啟動(dòng)時(shí)是單線程運(yùn)行的,這個(gè)線程被稱為 主線程。


然而,現(xiàn)代計(jì)算任務(wù)通常需要并行處理,主線程可以通過 pthread_create() 函數(shù)創(chuàng)建額外的線程來并行執(zhí)行任務(wù)。


這些額外的線程與主線程共享進(jìn)程的資源(如內(nèi)存空間、文件描述符等),但它們有獨(dú)立的執(zhí)行路徑。


pthread_create() 函數(shù)的定義如下:


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


函數(shù)參數(shù):

  • thread:這是一個(gè) pthread_t 類型的指針,指向存儲(chǔ)線程 ID 的變量。pthread_t 是用于唯一標(biāo)識(shí)線程的類型,當(dāng)創(chuàng)建線程成功時(shí),該變量會(huì)被賦值為新線程的 ID,在后續(xù)的線程管理中使用。

  • attr:這是一個(gè)指向 pthread_attr_t 類型的指針,用于設(shè)置線程的屬性。如果設(shè)置為 NULL,則使用線程的默認(rèn)屬性。這些屬性包括線程是否分離(detached)、棧大小等。如果需要設(shè)置特定的屬性,可以使用 pthread_attr_init() 和相關(guān)的屬性函數(shù)。

  • start_routine:這是線程執(zhí)行函數(shù)的指針。新線程創(chuàng)建后,會(huì)從這個(gè)函數(shù)開始執(zhí)行。該函數(shù)必須符合以下原型:


void* (*start_routine)(void *arg);


它接收一個(gè) void* 類型的參數(shù)(arg),并返回一個(gè) void* 類型的返回值。


  • arg:這是傳遞給 start_routine 函數(shù)的參數(shù)??梢允侨我忸愋偷闹羔?。如果不需要傳遞參數(shù),可以設(shè)置為 NULL。如果需要傳遞多個(gè)參數(shù),可以使用結(jié)構(gòu)體將它們打包后通過該指針傳入。


返回值:

  • 成功時(shí)返回 0。

  • 失敗時(shí)返回錯(cuò)誤號(hào),表示失敗的原因。例如,EAGAIN 表示系統(tǒng)資源不足無法創(chuàng)建新線程,EINVAL 表示傳入的屬性無效。


創(chuàng)建線程的關(guān)鍵點(diǎn):

  • 線程 ID: 每個(gè)線程都有唯一的 ID,用于區(qū)分線程。創(chuàng)建線程時(shí),pthread_create() 會(huì)將新線程的 ID 存儲(chǔ)在 pthread_t 類型的變量中,便于后續(xù)操作。

  • 線程屬性: 默認(rèn)情況下,線程使用系統(tǒng)的默認(rèn)屬性。如果需要更改線程的屬性,比如將其設(shè)置為 分離線程 或指定線程的棧大小,可以通過 pthread_attr_t 來設(shè)置。

  • 啟動(dòng)函數(shù)和參數(shù): 新線程會(huì)從 start_routine 函數(shù)開始執(zhí)行,并傳入 arg 參數(shù)??梢酝ㄟ^將多個(gè)參數(shù)封裝在結(jié)構(gòu)體中,一并傳遞給該函數(shù)。


當(dāng)一個(gè)新線程被創(chuàng)建后,它立即加入系統(tǒng)的 線程調(diào)度隊(duì)列,并在合適的時(shí)機(jī)獲取 CPU 執(zhí)行時(shí)間。

由于調(diào)度是由操作系統(tǒng)控制的,所以無法預(yù)料新創(chuàng)建的線程和主線程誰會(huì)先執(zhí)行。

如果程序?qū)€程的執(zhí)行順序有嚴(yán)格要求,可以使用同步機(jī)制(如 互斥鎖信號(hào)量)來控制線程間的執(zhí)行順序。

下面是一個(gè)創(chuàng)建線程并傳遞參數(shù)的簡單示例:


void* thread_function(void* arg) {    int* num = (int*)arg;    printf("New thread running with argument: %dn", *num);    return NULL;}
int main() {    pthread_t thread;    int arg = 42;
   // 創(chuàng)建線程,傳遞參數(shù) arg    if (pthread_create(&thread, NULL, thread_function, &arg) != 0) {        perror("pthread_create failed");        return 1;    }
   // 等待新線程執(zhí)行完畢    pthread_join(thread, NULL);
   printf("Main thread finishedn");    return 0;}


解釋:

  • 線程函數(shù) thread_function() 接收一個(gè) void* 類型的參數(shù),并將其強(qiáng)制轉(zhuǎn)換為 int* 類型,打印傳入的值。

  • 主線程 調(diào)用 pthread_create() 創(chuàng)建了一個(gè)新線程,并將 arg 作為參數(shù)傳遞給新線程的函數(shù) thread_function()。

  • 創(chuàng)建線程后,主線程調(diào)用 pthread_join() 等待新線程完成執(zhí)行。如果不使用 pthread_join(),主線程不會(huì)等待新線程結(jié)束,這可能導(dǎo)致程序提前退出。


2

終止線程

在 Linux 中,終止線程可以通過多種方式完成,不同的方式影響線程的退出行為和進(jìn)程的狀態(tài)管理。


我們?cè)敿?xì)說明幾種終止線程的常用方法。


  • return: 當(dāng)線程的 start 函數(shù)執(zhí)行 return 時(shí),線程正常終止,并返回指定的值,返回值可以通過 pthread_join() 獲取。

  • pthread_exit(): 線程可以通過顯式調(diào)用 pthread_exit() 來終止自身,pthread_exit() 允許線程在任何位置退出,返回的值也可以通過 pthread_join() 獲取。

  • pthread_cancel(): 通過 pthread_cancel() 可以請(qǐng)求取消一個(gè)線程,線程需要響應(yīng)取消請(qǐng)求才能終止。

  • exit() 和 _exit(): 當(dāng)進(jìn)程中的任意線程調(diào)用 exit()、_exit() 或 _Exit() 時(shí),整個(gè)進(jìn)程,包括所有線程,都會(huì)被終止。


2.1、通過 return 語句退出線程

線程的 start 函數(shù)(即傳遞給 pthread_create() 的函數(shù))在執(zhí)行完畢時(shí),可以直接使用 return 語句返回。這種方式會(huì)使線程正常退出,并將返回值作為線程的退出碼。


這與調(diào)用 pthread_exit() 類似。


void* thread_function(void* arg) {    // 執(zhí)行一些任務(wù)    int result = 42;    return (void*)result; // 通過 return 語句退出線程}


在上面的代碼中,線程執(zhí)行完 thread_function() 后,通過 return 返回 result,并且這個(gè)返回值可以通過 pthread_join() 函數(shù)在主線程中獲取。

2.2、通過 pthread_exit() 退出線程

pthread_exit() 是專門用于退出線程的函數(shù),它允許線程在任何位置顯式退出,而不是依賴于 return。


調(diào)用 pthread_exit() 后,線程的控制流會(huì)立即結(jié)束,不再執(zhí)行后續(xù)代碼。


pthread_exit() 函數(shù)原型:


void pthread_exit(void *retval);


參數(shù) retval: retval 是一個(gè) void* 類型的指針,指定線程的返回值,也就是線程的退出碼。這個(gè)值可以被其他線程通過 pthread_join() 獲取。


示例如下:


void* thread_function(void* arg) {    int* retval = (int*)arg;    printf("Thread exiting with value: %dn", *retval);    pthread_exit(retval); // 顯式退出線程并返回值}
int main() {    pthread_t thread;    int arg = 42;    int* retval;
   pthread_create(&thread, NULL, thread_function, &arg);    pthread_join(thread, (void**)&retval); // 獲取線程的退出碼
   printf("Thread returned: %dn", *retval);    return 0;}


解釋:

  • 在該示例中,pthread_exit() 顯式終止了線程,并返回參數(shù) arg 的值。

  • 主線程通過 pthread_join() 獲取了子線程的退出碼。


2.3、通過 exit()、_exit() 或 _Exit() 終止整個(gè)進(jìn)程

exit()、_exit() 和 _Exit() 不是用于終止單個(gè)線程的,而是用于終止整個(gè)進(jìn)程。


由于線程共享同一個(gè)進(jìn)程資源,如果任意一個(gè)線程調(diào)用這些函數(shù),整個(gè)進(jìn)程(包括所有線程)都會(huì)終止。

  • exit(): 正常終止進(jìn)程,執(zhí)行清理函數(shù)、關(guān)閉文件描述符等。

  • _exit() 和 _Exit(): 立即終止進(jìn)程,不執(zhí)行清理工作。


以下示例中,thread_function() 中調(diào)用了 exit(),導(dǎo)致整個(gè)進(jìn)程被終止,主線程也不會(huì)繼續(xù)執(zhí)行。


void* thread_function(void* arg) {    printf("Thread running...n");    exit(0); // 調(diào)用 exit(),導(dǎo)致整個(gè)進(jìn)程終止    return NULL;}
int main() {    pthread_t thread;
   pthread_create(&thread, NULL, thread_function, NULL);    pthread_join(thread, NULL);
   // 如果沒有被 exit() 終止,主線程會(huì)繼續(xù)執(zhí)行這行代碼    printf("Main thread finishedn");
   return 0;}


3

回收線程

在多線程編程中,當(dāng)線程結(jié)束后,其占用的資源不會(huì)立即被系統(tǒng)釋放,除非顯式回收這些資源,否則這些線程會(huì)變成 僵尸線程。


在 Linux 中,回收線程的操作與進(jìn)程的回收類似。


正如進(jìn)程中的父進(jìn)程可以使用 wait() 來回收子進(jìn)程的資源,線程中也需要通過 pthread_join() 來回收線程資源并獲取線程的退出狀態(tài)。


pthread_join() 是用于 等待指定線程終止并回收其資源 的函數(shù),它會(huì)阻塞調(diào)用線程直到目標(biāo)線程終止。


如果線程已經(jīng)終止,pthread_join() 將立即返回。


通過這個(gè)函數(shù),主線程或其他線程可以獲取目標(biāo)線程的退出狀態(tài),并清理其占用的資源,避免產(chǎn)生僵尸線程。


pthread_join() 的函數(shù)原型:


int pthread_join(pthread_t thread, void **retval);


函數(shù)參數(shù)說明:

  • thread: 這是目標(biāo)線程的線程 ID,pthread_join() 將等待這個(gè)線程終止。

  • retval: 這是一個(gè)指向 void* 類型的指針,指向保存線程返回值的內(nèi)存地址。如果目標(biāo)線程通過 pthread_exit() 或 return 語句返回了某個(gè)值,這個(gè)值將被存儲(chǔ)在 *retval 指向的內(nèi)存中。如果 retval 為 NULL,則表示不關(guān)心目標(biāo)線程的返回值。


返回值:

  • 成功時(shí)返回 0。

  • 如果調(diào)用失敗,pthread_join() 將返回一個(gè)錯(cuò)誤碼。例如,ESRCH 表示指定的線程不存在,EINVAL 表示線程不可被 pthread_join() 回收,或者調(diào)用線程嘗試等待自身終止。


以下例子中,線程執(zhí)行完 thread_function() 后通過 pthread_exit() 返回 result。


主線程調(diào)用 pthread_join() 等待線程結(jié)束,并成功獲取到了線程的返回值。


void* thread_function(void* arg) {    int result = 100;    printf("Thread running...n");    pthread_exit((void*)&result); // 顯式返回一個(gè)結(jié)果}
int main() {    pthread_t thread;    int* thread_result;
   // 創(chuàng)建線程    pthread_create(&thread, NULL, thread_function, NULL);
   // 回收線程并獲取返回值    pthread_join(thread, (void**)&thread_result);
   printf("Thread returned: %dn", *thread_result);    return 0;}


3.1、pthread_join() 的使用場(chǎng)景與注意事項(xiàng)

pthread_join() 是 阻塞函數(shù),它會(huì)一直等待指定線程結(jié)束。如果目標(biāo)線程需要執(zhí)行大量計(jì)算或處理,調(diào)用 pthread_join() 的線程將一直處于等待狀態(tài),直到目標(biāo)線程終止。


如果線程已經(jīng)結(jié)束,pthread_join() 將立即返回。


以下示例中,主線程在調(diào)用 pthread_join() 時(shí)會(huì)等待 5 秒,直到 worker_function() 執(zhí)行完畢為止。


void* worker_function(void* arg) {    sleep(5);  // 模擬一些長時(shí)間運(yùn)行的操作    return NULL;}
int main() {    pthread_t thread;
   pthread_create(&thread, NULL, worker_function, NULL);
   printf("Waiting for thread to finish...n");    pthread_join(thread, NULL); // 阻塞等待線程結(jié)束
   printf("Thread finished.n");    return 0;}


在進(jìn)程中,如果父進(jìn)程不回收子進(jìn)程,則子進(jìn)程會(huì)變?yōu)?僵尸進(jìn)程,占用系統(tǒng)資源。

同樣的,如果一個(gè)線程終止后,沒有被其他線程調(diào)用 pthread_join() 來回收,其內(nèi)存和其他資源也不會(huì)被立即釋放,這就導(dǎo)致了 僵尸線程 的問題。

僵尸線程不僅浪費(fèi)資源,而且如果僵尸線程累積過多,可能會(huì)導(dǎo)致應(yīng)用程序無法創(chuàng)建新的線程。

3.2、pthread_join() 與進(jìn)程回收的區(qū)別

雖然 pthread_join() 與進(jìn)程中的 waitpid() 類似,都是用于等待子線程(或子進(jìn)程)結(jié)束并獲取其退出狀態(tài),但二者之間有一些顯著的區(qū)別:


1、線程關(guān)系是對(duì)等的。

在多線程程序中,任何線程都可以調(diào)用 pthread_join() 來等待另一個(gè)線程的結(jié)束。即使是非創(chuàng)建該線程的線程,也可以調(diào)用 pthread_join() 來等待它的終止。線程之間沒有父子層級(jí)關(guān)系。


舉例來說,如果線程 A 創(chuàng)建了線程 B,線程 B 創(chuàng)建了線程 C,那么線程 A 可以等待線程 C 的結(jié)束,而不需要依賴線程 B。


這與進(jìn)程的父子層級(jí)結(jié)構(gòu)不同,父進(jìn)程是唯一可以調(diào)用 wait() 或 waitpid() 來等待子進(jìn)程終止的進(jìn)程。


2、pthread_join() 不支持非阻塞等待。

pthread_join() 是阻塞調(diào)用,不支持類似waitpid() 中的非阻塞模式(通過傳入 WNOHANG 標(biāo)志實(shí)現(xiàn))。


這意味著線程調(diào)用 pthread_join() 后必須等待目標(biāo)線程終止,不能做其他操作。如果需要更復(fù)雜的線程同步,通常需要引入其他機(jī)制,如 信號(hào)量、條件變量 等。


4

取消線程

通常情況下,線程會(huì)自行決定何時(shí)結(jié)束,比如通過調(diào)用 pthread_exit() 函數(shù)或者在其啟動(dòng)函數(shù)中執(zhí)行 return 語句。


但有些場(chǎng)景下,主線程或其他線程可能需要 強(qiáng)制終止 某個(gè)正在運(yùn)行的線程,這時(shí)就可以通過 取消請(qǐng)求 來實(shí)現(xiàn)。


通過調(diào)用 pthread_cancel(),可以向目標(biāo)線程發(fā)送一個(gè)取消請(qǐng)求,要求它終止。


pthread_cancel() 函數(shù)原型如下:


int pthread_cancel(pthread_t thread);


參數(shù)說明:

  • thread: 需要取消的目標(biāo)線程的線程 ID。


返回值:

  • 成功時(shí)返回 0。

  • 如果調(diào)用失敗,返回錯(cuò)誤碼,例如:ESRCH: 指定的線程不存在。


4.1、線程取消的響應(yīng)機(jī)制

目標(biāo)線程對(duì)取消請(qǐng)求的響應(yīng)方式可以由其自身決定。每個(gè)線程都有一個(gè) 取消狀態(tài)取消類型 來控制它對(duì)取消請(qǐng)求的響應(yīng):

4.1.1、取消狀態(tài)

取消狀態(tài)決定了線程是否允許響應(yīng)取消請(qǐng)求,線程可以通過調(diào)用 pthread_setcancelstate() 來修改其取消狀態(tài)。

  • PTHREAD_CANCEL_ENABLE: 表示線程 允許 響應(yīng)取消請(qǐng)求(這是默認(rèn)狀態(tài))。

  • PTHREAD_CANCEL_DISABLE: 表示線程 不允許 響應(yīng)取消請(qǐng)求。即使收到了取消請(qǐng)求,線程仍會(huì)繼續(xù)運(yùn)行,直到其取消狀態(tài)被重新設(shè)置為可取消。


pthread_setcancelstate() 函數(shù)原型:


int pthread_setcancelstate(int state, int *oldstate);


參數(shù):

  • state: 可以是 PTHREAD_CANCEL_ENABLE 或 PTHREAD_CANCEL_DISABLE,分別表示開啟或禁用取消請(qǐng)求的響應(yīng)。

  • oldstate: 如果不為 NULL,將保存原先的取消狀態(tài)。


示例如下:


pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); // 禁止取消請(qǐng)求pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);  // 允許取消請(qǐng)求


4.1.2、取消類型

取消類型決定了線程 何時(shí) 響應(yīng)取消請(qǐng)求。


可以通過調(diào)用 pthread_setcanceltype() 來設(shè)置線程的取消類型:

  • PTHREAD_CANCEL_DEFERRED: 線程將在 某些特定的取消點(diǎn) 響應(yīng)取消請(qǐng)求(例如調(diào)用 pthread_testcancel(),或進(jìn)行 I/O 操作時(shí))。這是默認(rèn)的取消類型。

  • PTHREAD_CANCEL_ASYNCHRONOUS: 線程在 收到取消請(qǐng)求的瞬間 就立即響應(yīng),可能導(dǎo)致線程在任意位置被取消。


pthread_setcanceltype() 函數(shù)原型:

int pthread_setcanceltype(int type, int *oldtype);


參數(shù):

  • type: 可以是 PTHREAD_CANCEL_DEFERRED 或 PTHREAD_CANCEL_ASYNCHRONOUS,分別表示延遲響應(yīng)取消或立即響應(yīng)取消。

  • oldtype: 如果不為 NULL,將保存原先的取消類型。


示例:


pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // 設(shè)置為立即響應(yīng)取消
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);      // 設(shè)置為延遲響應(yīng)取消


4.2、取消點(diǎn)與線程清理

當(dāng)線程的取消類型設(shè)置為 PTHREAD_CANCEL_DEFERRED 時(shí),線程只有在到達(dá)某些 取消點(diǎn) 時(shí)才會(huì)響應(yīng)取消請(qǐng)求。


取消點(diǎn)通常是一些耗時(shí)操作或系統(tǒng)調(diào)用,比如:


  • pthread_testcancel(): 顯式設(shè)置取消點(diǎn)。

  • 其他一些常見的系統(tǒng)調(diào)用,比如 I/O 操作、sleep()、select() 等,都是隱式取消點(diǎn)。



系統(tǒng)中還有許多函數(shù)可以作為取消點(diǎn),這里不再逐一列舉。您可以通過查看 man 手冊(cè)獲取更多信息,使用命令 man 7 pthreads 進(jìn)行查詢。 

pthread_testcancel() 函數(shù)原型:


void pthread_testcancel(void);


這個(gè)函數(shù)可以在代碼的任意位置顯式創(chuàng)建一個(gè)取消點(diǎn)。


調(diào)用 pthread_testcancel() 后,線程會(huì)檢查是否有取消請(qǐng)求,如果有,線程將在此處退出。


示例如下:


while (1) {    // 執(zhí)行一些任務(wù)    pthread_testcancel(); // 在循環(huán)中顯式設(shè)置取消點(diǎn),檢查是否有取消請(qǐng)求}


4.3、線程清理處理函數(shù)

在線程終止時(shí)(無論是正常結(jié)束還是被取消),可以使用 清理處理函數(shù) 來進(jìn)行資源清理。


清理處理函數(shù)可以確保線程在取消時(shí)能夠正確釋放資源,避免資源泄露。


使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 來設(shè)置清理函數(shù):

  • pthread_cleanup_push(void (*routine)(void *), void *arg):將一個(gè)清理函數(shù) routine 壓入棧,當(dāng)線程退出時(shí),系統(tǒng)將調(diào)用該函數(shù)。

  • pthread_cleanup_pop(int execute):將清理函數(shù)從棧中彈出,execute 表示是否執(zhí)行該函數(shù)。


以下例子中,當(dāng)線程收到取消請(qǐng)求后,它會(huì)在 pthread_testcancel() 函數(shù)處響應(yīng)取消請(qǐng)求并退出。


在線程退出時(shí),cleanup_handler() 會(huì)被調(diào)用以清理資源。


void cleanup_handler(void *arg) {    printf("Cleanup: %sn", (char *)arg);}
void* thread_function(void* arg) {    pthread_cleanup_push(cleanup_handler, "Thread resources"); // 設(shè)置清理函數(shù)    while (1) {        printf("Thread running...n");        sleep(1);        pthread_testcancel(); // 檢查是否有取消請(qǐng)求    }    pthread_cleanup_pop(1); // 1 表示執(zhí)行清理函數(shù)    return NULL;}
int main() {    pthread_t thread;    pthread_create(&thread, NULL, thread_function, NULL);
   sleep(3);  // 等待幾秒鐘    pthread_cancel(thread); // 發(fā)送取消請(qǐng)求    pthread_join(thread, NULL); // 等待線程結(jié)束    printf("Thread has been canceled.n");
   return 0;}


正確處理線程的取消操作對(duì)于復(fù)雜的多線程應(yīng)用程序至關(guān)重要,特別是在執(zhí)行長時(shí)間任務(wù)時(shí),靈活管理線程的取消狀態(tài)和清理行為能夠有效提高系統(tǒng)的穩(wěn)定性和可靠性。


  • pthread_cancel() 用于向目標(biāo)線程發(fā)送取消請(qǐng)求,要求其終止,但目標(biāo)線程是否終止取決于其取消狀態(tài)和取消類型。

  • 線程可以通過 pthread_setcancelstate() 來控制是否響應(yīng)取消請(qǐng)求,并通過 pthread_setcanceltype() 來控制何時(shí)響應(yīng)。

  • 在使用 延遲取消 的情況下,線程只有在特定的 取消點(diǎn) 處才會(huì)檢查取消請(qǐng)求,可以通過 pthread_testcancel() 顯式設(shè)置取消點(diǎn)。

  • 清理處理函數(shù) 確保線程在被取消時(shí)能夠正確釋放資源,避免資源泄露。


5

分離線程

默認(rèn)情況下,線程終止后,其資源不會(huì)立即被系統(tǒng)回收,除非有另一個(gè)線程通過 pthread_join() 函數(shù)顯式地等待該線程終止,回收其資源。


但如果某些線程的退出狀態(tài)和返回值對(duì)程序來說并不重要,且不希望手動(dòng)調(diào)用 pthread_join(),可以將該線程設(shè)置為 分離狀態(tài)。


分離狀態(tài)的線程在終止時(shí),系統(tǒng)會(huì)自動(dòng)回收它的資源。


要將線程設(shè)置為分離狀態(tài),可以調(diào)用 pthread_detach() 函數(shù)。


pthread_detach() 函數(shù)原型:


int pthread_detach(pthread_t thread);


參數(shù)說明:

  • thread: 需要分離的目標(biāo)線程的線程 ID。


返回值:

  • 成功時(shí)返回 0。

  • 如果調(diào)用失敗,返回錯(cuò)誤碼,例如:

    • ESRCH: 指定的線程不存在或已經(jīng)被回收。

    • EINVAL: 線程已經(jīng)處于分離狀態(tài)。


調(diào)用 pthread_detach() 后,指定的線程會(huì)進(jìn)入分離狀態(tài)。

處于分離狀態(tài)的線程在終止時(shí),系統(tǒng)會(huì)自動(dòng)回收其所有資源,而無需其他線程顯式調(diào)用 pthread_join()。

分離狀態(tài)是不可逆的,一旦線程被分離,就不能再通過 pthread_join() 獲取該線程的返回狀態(tài)或等待其結(jié)束。

以下例子中,創(chuàng)建了一個(gè)新線程,并通過 pthread_detach() 將其分離。之后,無需調(diào)用 pthread_join(),系統(tǒng)將在該線程終止時(shí)自動(dòng)回收它的資源。


pthread_t thread;pthread_create(&thread, NULL, thread_function, NULL);pthread_detach(thread); // 將該線程設(shè)置為分離狀態(tài)


線程不僅可以由其他線程分離,還可以通過調(diào)用 pthread_detach(pthread_self()) 來 分離自己。

這意味著該線程在終止時(shí)不需要其他線程來回收資源,系統(tǒng)將自動(dòng)處理。

示例如下:


void* thread_function(void* arg) {    pthread_detach(pthread_self()); // 分離自己    // 線程執(zhí)行的其他操作    pthread_exit(NULL);}


線程分離機(jī)制特別適用于以下幾種場(chǎng)景:

  • 不關(guān)心線程的返回值: 如果線程執(zhí)行的任務(wù)不需要返回值,且不希望其他線程顯式地等待它結(jié)束。

  • 避免僵尸線程: 僵尸線程是指已經(jīng)終止但資源未被回收的線程,長時(shí)間存在僵尸線程會(huì)消耗系統(tǒng)資源。將線程設(shè)置為分離狀態(tài),可以避免僵尸線程的產(chǎn)生。

  • 長時(shí)間運(yùn)行的后臺(tái)任務(wù): 如果線程運(yùn)行時(shí)間較長或是后臺(tái)任務(wù),而主線程不需要等待其結(jié)束,分離該線程可以簡化資源管理。


線程分離與 pthread_join() 的比較:


線程分離:

  • 使用 pthread_detach() 將線程設(shè)置為分離狀態(tài)。

  • 系統(tǒng)在線程終止時(shí)自動(dòng)回收資源。

  • 無法通過 pthread_join() 獲取線程的返回值或等待線程終止。


pthread_join():

  • 主動(dòng)調(diào)用 pthread_join() 等待指定線程終止并回收資源。

  • 可以獲取線程的返回值或終止?fàn)顟B(tài)。

  • 若沒有調(diào)用 pthread_join(),線程終止后會(huì)成為僵尸線程,直到其資源被回收。


線程分離在簡化多線程程序的資源管理方面非常有用,特別是對(duì)于一些無需等待或回收的線程,可以通過分離機(jī)制優(yōu)化程序的性能和穩(wěn)定性。

最后講兩點(diǎn)注意事項(xiàng):

  • 不可逆性: 一旦線程被設(shè)置為分離狀態(tài),就無法恢復(fù)到可被 pthread_join() 回收的狀態(tài)。如果你將某個(gè)線程分離,后續(xù)便無法獲取其返回值或等待它結(jié)束。

  • 線程同步問題: 如果某個(gè)線程執(zhí)行的任務(wù)需要與其他線程同步完成,則不應(yīng)將其分離。否則,主線程或其他線程可能無法等待該線程結(jié)束,導(dǎo)致任務(wù)未完成就繼續(xù)執(zhí)行。


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞: 嵌入式 Linux

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉