引言
在當(dāng)今信息技術(shù)日新月異的時(shí)代,多線程編程已經(jīng)成為了日常開發(fā)中不可或缺的一部分。Linux作為一種廣泛應(yīng)用的操作系統(tǒng),其對(duì)多線程編程的支持也相當(dāng)完善。本文將會(huì)介紹關(guān)于Linux多線程相關(guān)的知識(shí),其中包括了線程的概念、線程控制、線程分離等方面的內(nèi)容。如果你希望提升自己的多線程編程能力,本文將為你提供實(shí)用的技術(shù)指導(dǎo)和詳盡的知識(shí)儲(chǔ)備。讓我們一起來深入了解Linux多線程編程的奧秘吧!
一、 Linux線程概念
1. 什么是線程
- 在一個(gè)程序里的一個(gè)執(zhí)行路線就叫做線程(thread)。更準(zhǔn)確的定義是:線程是“一個(gè)進(jìn)程內(nèi)部的控制序列”。
- 一切進(jìn)程至少都有一個(gè)執(zhí)行線程。
- 線程在進(jìn)程內(nèi)部運(yùn)行,本質(zhì)是在進(jìn)程地址空間內(nèi)運(yùn)行。
- 在Linux系統(tǒng)中,在CPU眼中,看到的PCB都要比傳統(tǒng)的進(jìn)程更加輕量化。
- 透過進(jìn)程虛擬地址空間,可以看到進(jìn)程的大部分資源,將進(jìn)程資源合理分配給每個(gè)執(zhí)行流,就形成了線程執(zhí)行流。
2. 線程的概念
在Linux中,線程是指在同一個(gè)進(jìn)程內(nèi)部并發(fā)執(zhí)行的多個(gè)子任務(wù)。Linux將線程作為輕量級(jí)進(jìn)程(LWP)來實(shí)現(xiàn),每個(gè)線程共享相同的進(jìn)程地址空間和其他資源,包括文件描述符、信號(hào)處理器和其他內(nèi)核狀態(tài)。由于線程之間共享進(jìn)程的資源,因此線程之間的切換開銷通常比進(jìn)程之間的切換要小得多。
Linux使用POSIX線程庫(pthread)來支持多線程編程。通過pthread庫,開發(fā)人員可以方便地創(chuàng)建、控制和同步線程,實(shí)現(xiàn)多線程編程的各種功能。在Linux中,線程的創(chuàng)建和管理都是通過系統(tǒng)調(diào)用和pthread庫來完成的,開發(fā)人員可以使用pthread_create()
函數(shù)創(chuàng)建新線程,并使用pthread_join()
函數(shù)等來等待線程的結(jié)束,后面我們會(huì)詳細(xì)介紹。
在Linux中,線程與進(jìn)程一樣擁有自己的ID、寄存器上下文、棧和線程本地存儲(chǔ)(TLS)。線程可以通過共享內(nèi)存進(jìn)行通信,也可以使用線程同步機(jī)制來協(xié)調(diào)彼此的操作。在多核處理器上,Linux內(nèi)核會(huì)將不同的線程分配到不同的處理器核心上并行執(zhí)行,以提高系統(tǒng)的性能和響應(yīng)速度。
總的來說,Linux線程是在同一個(gè)進(jìn)程內(nèi)并發(fā)執(zhí)行的多個(gè)子任務(wù),通過共享進(jìn)程的資源和使用pthread庫來實(shí)現(xiàn)線程的創(chuàng)建和管理。在Linux環(huán)境下,充分利用線程可以提高程序的并發(fā)能力和性能表現(xiàn)。
3. 線程與進(jìn)程的區(qū)別
Linux線程和進(jìn)程的主要區(qū)別在于它們是操作系統(tǒng)對(duì)應(yīng)不同的執(zhí)行單元。
-
資源分配
- 進(jìn)程是資源分配的最小單位,每個(gè)進(jìn)程都有自己的地址空間、全局變量、堆棧、文件描述符等系統(tǒng)資源。
- 線程是CPU調(diào)度的最小單位,多個(gè)線程可以共享同一個(gè)進(jìn)程的資源,包括地址空間、全局變量、文件描述符等。
-
切換開銷
- 因?yàn)榫€程共享進(jìn)程資源,因此線程之間的切換開銷比進(jìn)程之間的切換要小得多。
- 線程的上下文切換只需要保存處理器寄存器和棧指針,而進(jìn)程切換需要保存整個(gè)進(jìn)程的上下文信息,包括內(nèi)存映像、堆棧、寄存器等。
-
通信機(jī)制
- 進(jìn)程之間通常使用IPC(Inter-Process Communication)機(jī)制來進(jìn)行進(jìn)程間通信,例如管道、消息隊(duì)列、共享內(nèi)存和信號(hào)量等。
- 線程之間可以通過共享內(nèi)存、互斥鎖、條件變量等同步機(jī)制來進(jìn)行通信和協(xié)調(diào)。
-
并發(fā)能力
- 由于線程共享進(jìn)程資源和較小的切換開銷,因此線程可以更輕松地實(shí)現(xiàn)并發(fā)執(zhí)行,提高程序的并發(fā)處理能力和性能表現(xiàn)。
-
安全性
- 線程共享進(jìn)程資源,因此線程之間操作共享數(shù)據(jù)可能會(huì)引起競(jìng)態(tài)條件等并發(fā)問題,需要使用同步機(jī)制來協(xié)調(diào)線程的操作。
- 進(jìn)程之間不共享地址空間,可以通過IPC機(jī)制來實(shí)現(xiàn)安全的進(jìn)程間通信。
?進(jìn)程和線程的關(guān)系如下圖:
4. 線程異常
-
線程死鎖:線程之間相互等待對(duì)方釋放資源,導(dǎo)致所有線程都無法繼續(xù)執(zhí)行的情況。
-
競(jìng)態(tài)條件:多個(gè)線程同時(shí)訪問共享的資源,導(dǎo)致意外的結(jié)果或者數(shù)據(jù)損壞。
-
內(nèi)存泄漏:線程未正確釋放動(dòng)態(tài)分配的內(nèi)存,導(dǎo)致系統(tǒng)資源耗盡。
-
線程間通信問題:線程之間的通信出現(xiàn)問題,例如數(shù)據(jù)丟失、阻塞等情況。
-
未捕獲的異常:線程中的代碼拋出未捕獲的異常,導(dǎo)致線程意外終止。
?當(dāng)一個(gè)線程出現(xiàn)嚴(yán)重的異常導(dǎo)致崩潰時(shí),會(huì)觸發(fā)進(jìn)程內(nèi)的異常處理機(jī)制。在大多數(shù)操作系統(tǒng)中,異常會(huì)導(dǎo)致信號(hào)被發(fā)送給進(jìn)程,例如SIGSEGV(段錯(cuò)誤)或SIGFPE(浮點(diǎn)異常)。默認(rèn)情況下,這些信號(hào)會(huì)終止整個(gè)進(jìn)程。
??注意:線程是進(jìn)程的執(zhí)行分支,線程出異常,就類似進(jìn)程出異常,進(jìn)而觸發(fā)信號(hào)機(jī)制,終止進(jìn)程,進(jìn)程終止,該進(jìn)程內(nèi)的所有線程也就隨即退出。
二、Linux線程控制
1. POSIX線程庫
在Linux系統(tǒng)中,POSIX線程庫(也稱為pthread庫)是一套用于多線程編程的標(biāo)準(zhǔn)接口。它基于POSIX標(biāo)準(zhǔn)(Portable Operating System Interface)定義了一組函數(shù)和數(shù)據(jù)類型,使得開發(fā)者可以方便地進(jìn)行多線程程序的開發(fā)。
POSIX線程庫的設(shè)計(jì)目標(biāo)是提供一個(gè)可移植、高效和可靠的多線程編程接口。它已經(jīng)成為類UNIX系統(tǒng)上標(biāo)準(zhǔn)的多線程編程接口,并在Linux系統(tǒng)中得到廣泛應(yīng)用。開發(fā)者可以使用POSIX線程庫編寫具有良好可移植性的多線程程序,無需關(guān)心底層操作系統(tǒng)的差異。
2. 創(chuàng)建線程 pthread_create() 函數(shù)
在Linux系統(tǒng)中,線程的創(chuàng)建是通過POSIX線程庫(pthread庫)提供的函數(shù)來實(shí)現(xiàn)的
(1)頭文件
pthread_create()
函數(shù)的使用需要包含pthread庫的頭文件pthread.h
#include <pthread.h>
(2)函數(shù)原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
(3)參數(shù)解釋
-
thread:指向
pthread_t
類型的指針,用于存儲(chǔ)新線程的標(biāo)識(shí)符。在函數(shù)成功返回時(shí),該指針被設(shè)置為新線程的標(biāo)識(shí)符,可以用于后續(xù)操作。 -
attr:指向
pthread_attr_t
類型的指針,用于設(shè)置線程的屬性,通??梢詡魅?nullptr
,表示使用默認(rèn)屬性。如果需要設(shè)置線程的屬性,可以使用 pthread_attr_init() 函數(shù)初始化屬性對(duì)象,并使用 pthread_attr_setxxx() 函數(shù)設(shè)置屬性。 -
start_routine:指向線程函數(shù)的指針,即新線程的執(zhí)行體。該函數(shù)應(yīng)該以
void* func(void*)
的形式定義,即帶有一個(gè) void 類型指針參數(shù),返回一個(gè)void
類型指針。線程函數(shù)的返回值將作為線程的退出狀態(tài),可以通過pthread_join()
函數(shù)獲取。 -
arg:傳遞給線程函數(shù)的參數(shù),它必須是一個(gè)
void
類型指針,開發(fā)者需要自行處理類型轉(zhuǎn)換。
(4)返回值
- 如果成功創(chuàng)建了新線程,則函數(shù)返回 0;
- 如果失敗,則返回一個(gè)非零值,表示出現(xiàn)了錯(cuò)誤。在出錯(cuò)的情況下,可以使用
perror()
函數(shù)輸出錯(cuò)誤信息,也可以使用strerror()
函數(shù)獲取錯(cuò)誤信息。
(5)使用示例
#include <stdio.h>
#include <pthread.h>
void* thread_function(void* arg) {
int tid = *(int*)arg;
printf("This is thread %d.\n", tid);
pthread_exit(NULL);
}
int main() {
pthread_t tid[3];
int i, rc;
// 創(chuàng)建三個(gè)新線程
for (i = 0; i < 3; i++) {
rc = pthread_create(&tid[i], NULL, thread_function, (void*)&i);
if (rc != 0) {
fprintf(stderr, "Failed to create new thread.\n");
return 1;
}
}
// 等待所有新線程結(jié)束
for (i = 0; i < 3; i++) {
rc = pthread_join(tid[i], NULL);
if (rc != 0) {
fprintf(stderr, "Failed to join the thread.\n");
return 1;
}
}
printf("All threads exit.\n");
return 0;
}
通過上面的步驟,可以在 Linux 系統(tǒng)下成功創(chuàng)建并執(zhí)行新的線程。需要注意的是,調(diào)用 pthread_create()
函數(shù)時(shí)傳遞給線程函數(shù)的參數(shù)必須是指向整型變量的指針,否則可能會(huì)出現(xiàn)不可預(yù)期的錯(cuò)誤。
3. 線程ID及進(jìn)程地址空間布局
(1)進(jìn)程地址空間布局
進(jìn)程地址空間布局是指操作系統(tǒng)在內(nèi)存中為每個(gè)進(jìn)程分配的地址空間的布局方式。以下是典型的Linux進(jìn)程地址空間布局:
-
代碼段(Text Segment):
代碼段存儲(chǔ)了可執(zhí)行程序的機(jī)器指令。它通常是只讀的,并且在內(nèi)存中只有一份,用于所有執(zhí)行該程序的進(jìn)程。 -
數(shù)據(jù)段(Data Segment):
數(shù)據(jù)段存儲(chǔ)了全局變量和靜態(tài)變量。它包括了初始化的數(shù)據(jù)和非初始化的BSS段(Block Started by Symbol)。數(shù)據(jù)段通常是可讀寫的。 -
堆(Heap):
堆是動(dòng)態(tài)分配內(nèi)存的區(qū)域。在運(yùn)行時(shí),通過調(diào)用malloc()
、calloc()
等函數(shù)分配堆內(nèi)存。堆的大小不固定,可以根據(jù)需要?jiǎng)討B(tài)增長(zhǎng)或縮小。 -
棧(Stack):
棧用于存儲(chǔ)函數(shù)調(diào)用、局部變量和函數(shù)參數(shù)等信息。每個(gè)線程都有自己的棧,用于保存線程特定的上下文信息。棧的大小通常是固定的。 -
共享庫(Shared Libraries):
共享庫存儲(chǔ)了被多個(gè)進(jìn)程共享的代碼和數(shù)據(jù)。它們被加載到內(nèi)存中,并映射到每個(gè)進(jìn)程的地址空間中。 -
內(nèi)核空間(Kernel Space):
內(nèi)核空間是由操作系統(tǒng)內(nèi)核使用的內(nèi)存區(qū)域,不屬于進(jìn)程的地址空間。它包括操作系統(tǒng)內(nèi)核的代碼和數(shù)據(jù)結(jié)構(gòu)。
(2)線程ID pthread_self() 函數(shù)
線程ID(Thread ID)是操作系統(tǒng)分配給每個(gè)線程的唯一標(biāo)識(shí)符。在不同的操作系統(tǒng)中,線程ID的表示方式和取值范圍可能會(huì)有所不同。pthread_self()
函數(shù)是一個(gè)POSIX線程庫中的函數(shù),用于獲取當(dāng)前線程的線程ID。它的原型如下:
pthread_t pthread_self(void);
該函數(shù)沒有參數(shù),返回類型為pthread_t
,即線程ID的類型。
使用pthread_self()
函數(shù)可以在多線程程序中獲取當(dāng)前線程的線程ID。每個(gè)線程在創(chuàng)建時(shí)都會(huì)被分配一個(gè)唯一的線程ID,可以通過該ID來標(biāo)識(shí)和區(qū)分不同的線程。
下面是一個(gè)簡(jiǎn)單的示例代碼,演示了如何使用pthread_self()
函數(shù)獲取當(dāng)前線程的線程ID:
#include <stdio.h>
#include <pthread.h>
void* thread_func(void* arg) {
pthread_t tid = pthread_self();
printf("Thread ID: %lu\n", tid);
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
pthread_join(tid, NULL);
return 0;
}
在上述示例中,主線程創(chuàng)建了一個(gè)新線程,并通過pthread_create()
函數(shù)啟動(dòng)線程執(zhí)行thread_func()
函數(shù)。在thread_func()
函數(shù)中,調(diào)用pthread_self()
函數(shù)獲取當(dāng)前線程的線程ID,并將其打印輸出。
??注意:線程ID的類型pthread_t
可能是一個(gè)不透明的數(shù)據(jù)類型,具體實(shí)現(xiàn)取決于操作系統(tǒng)和編譯器。在上述示例中,使用%lu
格式指定符打印無符號(hào)長(zhǎng)整型,以與pthread_t
類型匹配。在不同的系統(tǒng)和編譯環(huán)境中,可能需要根據(jù)具體情況調(diào)整打印格式。
4. 線程等待 pthread_join() 函數(shù)
?線程等待是一種同步機(jī)制,會(huì)導(dǎo)致線程之間的阻塞和等待。在設(shè)計(jì)多線程程序時(shí),需要合理地安排線程的執(zhí)行順序和等待關(guān)系,以避免死鎖、饑餓等問題。pthread_join()
函數(shù)是一個(gè)POSIX線程庫中的函數(shù),用于等待指定的線程結(jié)束并回收其資源。
(1)頭文件
pthread_join()
函數(shù)的使用需要包含pthread庫的頭文件pthread.h
#include <pthread.h>
(2)函數(shù)原型
int pthread_join(pthread_t thread, void **retval);
(3)參數(shù)解釋
-
thread
參數(shù)是要等待的目標(biāo)線程的線程ID, -
retval
參數(shù)用于接收目標(biāo)線程的返回值(如果有)。pthread_join()
函數(shù)會(huì)阻塞調(diào)用線程,直到目標(biāo)線程結(jié)束為止,并且可以獲取目標(biāo)線程的返回值。
(4)返回值
pthread_join()
函數(shù)的返回值表示線程的終止?fàn)顟B(tài),具體取值如下:
- 如果線程的返回值已經(jīng)被存放到
value_ptr
指向的內(nèi)存中,則返回 0。 - 如果指定的線程在執(zhí)行過程中被取消,則返回
PTHREAD_CANCELED
。 - 如果調(diào)用該函數(shù)時(shí)出現(xiàn)錯(cuò)誤,則返回相應(yīng)的錯(cuò)誤代碼。
(5)使用示例
下面是一個(gè)簡(jiǎn)單的示例代碼,演示了如何使用pthread_join()
函數(shù)等待子線程結(jié)束并獲取其返回值:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* thread_func(void* arg) {
int* result = (int*)malloc(sizeof(int));
*result = 42;
printf("Thread is about to exit\n");
pthread_exit((void*)result); // 終止線程,并返回 result
}
int main() {
pthread_t tid;
void* ret_val;
pthread_create(&tid, NULL, thread_func, NULL);
pthread_join(tid, &ret_val); // 獲取線程的返回值
if (ret_val) {
printf("Thread returned: %d\n", *((int*)ret_val));
free(ret_val); // 釋放返回值對(duì)應(yīng)的內(nèi)存
} else {
printf("Thread returned NULL\n");
}
return 0;
}
在上面的示例中,我們創(chuàng)建了一個(gè)新線程,線程函數(shù)中使用了 pthread_exit()
函數(shù)來結(jié)束線程并返回一個(gè)整數(shù)值。在主線程中,我們通過 pthread_join()
函數(shù)等待線程的終止,并獲取了線程的返回值。
??注意:pthread_join()
函數(shù)會(huì)使調(diào)用線程進(jìn)入阻塞狀態(tài),直到目標(biāo)線程結(jié)束。如果不關(guān)心目標(biāo)線程的返回值,也可以將retval
參數(shù)設(shè)置為NULL
。另外,在多線程程序中,需要特別注意線程的安全退出和資源回收,以避免產(chǎn)生懸掛線程或資源泄漏的問題。
5. 線程終止
(1)線程終止的三種方法
-
線程函數(shù)返回:線程函數(shù)執(zhí)行完畢并從函數(shù)中返回,線程會(huì)自動(dòng)終止。線程函數(shù)可以通過返回一個(gè)值來傳遞結(jié)果給線程的創(chuàng)建者。
-
調(diào)用
pthread_exit()
函數(shù):線程可以顯式地調(diào)用pthread_exit()
函數(shù)來終止自己。這個(gè)函數(shù)接受一個(gè)參數(shù)作為線程的返回值,可以被其他線程通過調(diào)用pthread_join()
函數(shù)獲取。 -
取消線程:線程可以被其他線程取消。調(diào)用
pthread_cancel(pthread_t thread)
函數(shù)可以請(qǐng)求取消指定的線程。被取消的線程可以選擇在適當(dāng)?shù)臅r(shí)機(jī)終止自己,或者忽略取消請(qǐng)求繼續(xù)執(zhí)行。
(2)pthread_exit() 函數(shù)
pthread_exit()
函數(shù)是用于終止當(dāng)前線程并返回一個(gè)值的 POSIX 線程庫函數(shù)。該函數(shù)的原型如下所示:
void pthread_exit(void* value_ptr);
-
value_ptr
:表示線程的返回值,可以是任意類型的指針。當(dāng)線程調(diào)用pthread_exit()
函數(shù)時(shí),會(huì)將value_ptr
指向的內(nèi)容作為線程的返回值。
pthread_exit()
函數(shù)允許線程在執(zhí)行過程中隨時(shí)退出,并返回一個(gè)值。這個(gè)返回值可以被其他線程通過調(diào)用 pthread_join()
函數(shù)獲取,從而實(shí)現(xiàn)線程間的數(shù)據(jù)交互和結(jié)果傳遞。
下面是一個(gè)簡(jiǎn)單的示例,演示了如何在線程中使用 pthread_exit()
函數(shù)來結(jié)束線程并返回一個(gè)值:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* thread_func(void* arg) {
int* result = (int*)malloc(sizeof(int));
*result = 42;
printf("Thread is about to exit\n");
pthread_exit((void*)result); // 終止線程,并返回 result
}
int main() {
pthread_t tid;
void* ret_val;
pthread_create(&tid, NULL, thread_func, NULL);
pthread_join(tid, &ret_val); // 獲取線程的返回值
printf("Thread returned: %d\n", *((int*)ret_val));
free(ret_val); // 釋放返回值對(duì)應(yīng)的內(nèi)存
return 0;
}
在上面的示例中,我們創(chuàng)建了一個(gè)新線程,線程函數(shù)中使用了 pthread_exit()
函數(shù)來結(jié)束線程并返回一個(gè)整數(shù)值。在主線程中,我們通過 pthread_join()
函數(shù)獲取了線程的返回值,并打印輸出了該值。
(3)pthread_cancel() 函數(shù)
pthread_cancel()
函數(shù)是 POSIX 線程庫中用于取消指定線程的函數(shù)。該函數(shù)的原型如下所示:
int pthread_cancel(pthread_t thread);
-
thread
:表示要取消的線程的標(biāo)識(shí)符。
pthread_cancel()
函數(shù)會(huì)向指定線程發(fā)送一個(gè)取消請(qǐng)求,并嘗試終止該線程的執(zhí)行。但是,線程是否會(huì)被成功取消取決于多個(gè)因素,包括線程自身的取消狀態(tài)和取消點(diǎn)的設(shè)置。
pthread_cancel()
函數(shù)只是發(fā)送一個(gè)取消請(qǐng)求并立即返回,并不能保證目標(biāo)線程會(huì)立即終止。目標(biāo)線程可以選擇忽略取消請(qǐng)求或者在適當(dāng)?shù)娜∠c(diǎn)進(jìn)行處理。
取消點(diǎn)(cancellation point)是線程中的一些特定位置,線程在這些位置上可以檢查是否有取消請(qǐng)求,并決定是否終止自己的執(zhí)行。常見的取消點(diǎn)包括 I/O 操作、阻塞的系統(tǒng)調(diào)用等。
如果目標(biāo)線程成功響應(yīng)了取消請(qǐng)求,并在取消點(diǎn)終止了執(zhí)行,那么取消狀態(tài)將被設(shè)置為已取消。可以通過調(diào)用 pthread_setcancelstate()
和 pthread_setcanceltype()
函數(shù)來控制線程的取消狀態(tài)和取消類型。
下面是一個(gè)示例,演示了如何使用 pthread_cancel()
函數(shù)來取消線程的執(zhí)行:
#include <stdio.h>
#include <pthread.h>
void* thread_func(void* arg) {
while (1) {
// 線程執(zhí)行的邏輯
}
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
// 在主線程中取消子線程的執(zhí)行
pthread_cancel(tid);
pthread_join(tid, NULL); // 等待線程結(jié)束
return 0;
}
在上面的示例中,我們創(chuàng)建了一個(gè)新線程,并在主線程中調(diào)用 pthread_cancel()
函數(shù)來取消子線程的執(zhí)行。接著,我們使用 pthread_join()
函數(shù)等待子線程的終止。
??注意:在使用 pthread_cancel()
函數(shù)取消線程時(shí),應(yīng)確保目標(biāo)線程處于可取消狀態(tài),并且在適當(dāng)?shù)奈恢迷O(shè)置了取消點(diǎn)。否則,取消請(qǐng)求可能被忽略,導(dǎo)致線程無法正確終止。
三、分離線程
1. joinable與線程分離
“joinable” 和線程分離是兩種不同的線程狀態(tài)。
- “joinable” 狀態(tài)的線程是指可以被其他線程顯式等待和回收資源的線程。在 POSIX 線程庫中,默認(rèn)情況下,創(chuàng)建的線程是可連接狀態(tài)(joinable)??蛇B接狀態(tài)的線程需要使用
pthread_join()
函數(shù)來等待其終止,并獲取其返回值(如果有)。 - 線程分離是指將線程屬性設(shè)置為分離狀態(tài),使得線程在終止時(shí)可以自動(dòng)釋放相關(guān)資源,而無需等待其他線程顯式對(duì)其進(jìn)行回收。分離線程通常用于不需要獲取線程返回值或進(jìn)行線程同步的場(chǎng)景。
2. 分離線程 pthread_detach() 函數(shù)
pthread_detach()
函數(shù)是 POSIX 線程庫中的一個(gè)函數(shù),用于將指定線程設(shè)置為分離狀態(tài),即使該線程在終止時(shí)可以自動(dòng)釋放相關(guān)資源,而無需等待其他線程顯式對(duì)其進(jìn)行回收。
(1)頭文件
pthread_detach()
函數(shù)的使用需要包含pthread庫的頭文件pthread.h
#include <pthread.h>
(2)函數(shù)原型
int pthread_detach(pthread_t thread);
(3)參數(shù)解釋
-
thread
:表示要設(shè)置為分離狀態(tài)的線程的標(biāo)識(shí)符。
(4)返回值
pthread_detach()
函數(shù)的返回值為 0 表示調(diào)用成功,返回值為非零表示調(diào)用失敗。失敗的原因可能是參數(shù)不正確或者內(nèi)部出現(xiàn)了錯(cuò)誤。
??注意:線程在被設(shè)置為分離狀態(tài)之前,必須處于可連接狀態(tài)。否則,pthread_detach()
函數(shù)將無法將其設(shè)置為分離狀態(tài),并返回一個(gè)錯(cuò)誤碼。
(5)使用示例
下面是一個(gè)示例,演示了如何使用 pthread_detach()
函數(shù)將線程設(shè)置為分離狀態(tài):
#include <stdio.h>
#include <pthread.h>
void* thread_func(void* arg) {
// 線程執(zhí)行的邏輯
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
// 將線程設(shè)置為分離狀態(tài)
pthread_detach(tid);
// 不需要使用 pthread_join() 函數(shù)進(jìn)行回收
return 0;
}
在上面的示例中,我們創(chuàng)建了一個(gè)新線程,并使用 pthread_detach()
函數(shù)將其設(shè)置為分離狀態(tài)。由于該線程已經(jīng)處于分離狀態(tài),因此在主線程中無需使用 pthread_join()
函數(shù)進(jìn)行回收。
四、線程的優(yōu)缺點(diǎn)
線程是一種輕量級(jí)的執(zhí)行單元,可以在一個(gè)進(jìn)程內(nèi)并發(fā)執(zhí)行多個(gè)任務(wù)。線程有以下優(yōu)點(diǎn)和缺點(diǎn):
?優(yōu)點(diǎn)
- 并發(fā)執(zhí)行:線程允許多個(gè)任務(wù)同時(shí)執(zhí)行,提高了程序的運(yùn)行效率和響應(yīng)速度??梢猿浞掷枚嗪颂幚砥鞯挠?jì)算能力。
- 共享數(shù)據(jù):線程可以共享同一個(gè)進(jìn)程的內(nèi)存空間,方便數(shù)據(jù)之間的共享和通信。不同線程之間可以直接讀取和修改同一塊內(nèi)存區(qū)域的數(shù)據(jù),簡(jiǎn)化了多任務(wù)編程的復(fù)雜性。
- 資源高效:線程的創(chuàng)建和銷毀消耗的資源相對(duì)較少,線程切換的開銷也較小。相比于進(jìn)程,線程更加輕量級(jí)。
- 邏輯清晰:使用線程可以將程序分解成多個(gè)獨(dú)立的執(zhí)行單元,每個(gè)線程負(fù)責(zé)不同的任務(wù),使得程序的邏輯結(jié)構(gòu)更加清晰、模塊化。
?缺點(diǎn)
- 同步和共享問題:多個(gè)線程訪問共享數(shù)據(jù)時(shí)需要進(jìn)行同步操作,以避免數(shù)據(jù)競(jìng)爭(zhēng)和不一致的結(jié)果。需要使用鎖、信號(hào)量等機(jī)制來保護(hù)共享資源,增加了編程的復(fù)雜性。
- 錯(cuò)誤管理困難:線程共享同一進(jìn)程的內(nèi)存空間,一個(gè)線程對(duì)共享資源的錯(cuò)誤操作可能會(huì)影響其他線程的正常執(zhí)行,導(dǎo)致難以追蹤和調(diào)試錯(cuò)誤。
- 調(diào)試和測(cè)試復(fù)雜:由于線程并發(fā)執(zhí)行,線程之間的交互和調(diào)試相對(duì)復(fù)雜。當(dāng)程序出現(xiàn)問題時(shí),需要仔細(xì)分析各個(gè)線程的執(zhí)行順序和交互情況,增加了調(diào)試和測(cè)試的難度。
- 資源競(jìng)爭(zhēng):多個(gè)線程同時(shí)訪問共享資源時(shí)可能引發(fā)資源競(jìng)爭(zhēng)問題,如死鎖、饑餓等。需要合理設(shè)計(jì)和管理線程的同步和互斥機(jī)制,以避免資源競(jìng)爭(zhēng)問題。
五、線程用途
- 合理的使用多線程,能提高CPU密集型程序的執(zhí)行效率。
- 合理的使用多線程,能提高IO密集型程序的用戶體驗(yàn)。(如生活中我們一邊寫代碼一邊下載開發(fā)工具,就是多線程運(yùn)行的一種表現(xiàn))
溫馨提示
感謝您對(duì)博主文章的關(guān)注與支持!如果您喜歡這篇文章,可以點(diǎn)贊、評(píng)論和分享給您的同學(xué),這將對(duì)我提供巨大的鼓勵(lì)和支持。另外,我計(jì)劃在未來的更新中持續(xù)探討與本文相關(guān)的內(nèi)容。我會(huì)為您帶來更多關(guān)于Linux以及C++編程技術(shù)問題的深入解析、應(yīng)用案例和趣味玩法等。如果感興趣的話可以關(guān)注博主的更新,不要錯(cuò)過任何精彩內(nèi)容!文章來源:http://www.zghlxwxcb.cn/news/detail-753702.html
再次感謝您的支持和關(guān)注。我們期待與您建立更緊密的互動(dòng),共同探索Linux、C++、算法和編程的奧秘。祝您生活愉快,排便順暢!文章來源地址http://www.zghlxwxcb.cn/news/detail-753702.html
到了這里,關(guān)于【探索Linux】—— 強(qiáng)大的命令行工具 P.19(多線程 | 線程的概念 | 線程控制 | 分離線程)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!