Linux線程 | 創建 終止 回收 分離
一、線程簡介

-
線程是參與系統調度的最小單位。它被包含在進程之中,是進程中的實際運行單位。
-
一個進程中可以創建多個線程,多個線程實現并發運行,每個線程執行不同的任務。
-
每個線程都有其對應的標識,稱為線程 ID,線程 ID 使用
pthread_t數據類型來表示。

二、線程的創建
線程是輕量級的并發執行單元,通過調用Linux系統提供的pthread庫中的函數來創建和管理線程。
- 包含頭文件:
#include <pthread.h>
- 定義線程函數:
線程函數是線程實際執行的函數,可以是任何可以被調用的函數。線程函數的原型如下:
void* thread_function(void* arg);
其中arg是傳遞給線程函數的參數,可以是任何類型的數據。線程函數的返回值為void*類型,可以返回任何類型的數據。
- 創建線程:
創建線程需要調用pthread_create函數。該函數的原型如下:
int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);
| 參數 | 類型 | 描述 |
|---|---|---|
thread |
pthread_t * |
用于存儲新線程標識符的指針 |
attr |
const pthread_attr_t * |
用于指定新線程的屬性,如棧大小、調度策略等,可以為 NULL,表示使用默認屬性 |
start_routine |
void *(*)(void *) |
新線程的起始函數,需要返回 void 指針類型的結果,并且帶有一個 void 指針類型的參數 |
arg |
void * |
傳遞給新線程起始函數的參數,可以為 NULL |
| 返回值 | int |
0 表示成功,非 0 表示失敗,錯誤代碼保存在 errno 中 |
?? 注意:在調用 pthread_create() 函數之后,新線程的執行與調用線程并行進行,它們之間沒有特定的執行順序。
下面是一個創建線程的例子:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("這是線程函數,arg=%d, i=%d\n", *(int *)arg, i);
sleep(1);
}
pthread_exit(NULL);
}
int main()
{
pthread_t tid; // 線程標識符
int arg = 123; // 傳遞給線程函數的參數
// 創建新線程
if (pthread_create(&tid, NULL, thread_func, &arg) != 0) {
printf("線程創建失敗!\n");
return 1;
}
// 等待線程結束并回收資源
if (pthread_join(tid, NULL) != 0) {
printf("線程回收失敗!\n");
return 1;
}
printf("線程結束!\n");
return 0;
}

三、 線程的終止
線程的終止有兩種方式:自然終止和強制終止。
線程的自然終止是指線程執行完它的工作后自動退出,而強制終止是指在程序運行過程中,主線程或其他線程顯式地終止一個正在運行的線程。
線程自然終止
線程可以通過調用pthread_exit函數來實現自然終止。pthread_exit函數的原型如下:
void pthread_exit(void *retval);
pthread_exit函數 無返回值,其中,參數retval是線程的退出狀態,可以通過pthread_join函數獲取。
下面是一個簡單的例子,演示如何使用pthread_exit函數終止一個線程:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("這是線程函數,i=%d\n", i);
sleep(1);
}
pthread_exit((void *) "線程正常結束!");
}
int main()
{
pthread_t tid; // 線程標識符
// 創建新線程
if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
printf("線程創建失敗!\n");
return 1;
}
// 等待線程結束并回收資源
void *retval;
if (pthread_join(tid, &retval) != 0) {
printf("線程回收失敗!\n");
return 1;
}
printf("%s\n", (char *)retval);
printf("線程結束!\n");
return 0;
}
上面的示例程序中,我們在線程函數中調用pthread_exit函數來終止線程,并返回一個字符串作為退出狀態。
在主線程中,我們使用pthread_join函數等待線程結束,并通過指針retval獲取線程的退出狀態。
線程強制終止
在Linux中,線程的強制終止可以使用pthread_cancel函數來實現。pthread_cancel函數的原型如下:
int pthread_cancel(pthread_t thread);
其中,參數thread是要取消的線程標識符。當pthread_cancel函數被調用時,被取消的線程將立即退出。
| 參數 | 類型 | 描述 |
|---|---|---|
thread |
pthread_t |
要取消的線程標識符 |
| 返回值 | int |
0 表示成功,非 0 表示失敗,錯誤代碼保存在 errno 中 |
??注意:調用 pthread_cancel() 函數只是向指定線程發送一個取消請求,讓指定線程盡快退出執行,而不會立即終止它的執行。
線程在接收到取消請求后,可以通過調用 pthread_setcancelstate() 和 pthread_setcanceltype() 函數來指定如何響應請求,這里不再展開說明。
下面是一個簡單的例子,演示如何使用pthread_cancel函數強制終止一個線程:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("這是線程函數,i=%d\n", i);
sleep(1);
}
pthread_exit((void *) "線程正常結束!");
}
int main()
{
pthread_t tid; // 線程標識符
// 創建新線程
if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
printf("線程創建失敗!\n");
return 1;
}
// 等待一段時間后強制終止線程
sleep(2);
if (pthread_cancel(tid) != 0) {
printf("線程取消失敗!\n");
return 1;
}
// 等待線程結束并回收資源
void *retval;
if (pthread_join(tid, &retval) != 0) {
printf("線程回收失敗!\n");
return 1;
}
if (retval == PTHREAD_CANCELED) {
printf("線程被取消!\n");
} else {
printf("%s\n", (char *)retval);
}
printf("線程結束!\n");
return 0;
}
上面的示例程序中,主線程調用了pthread_cancel函數,強制終止了子線程。
在子線程函數中,我們使用pthread_exit函數返回了一個字符串,如果子線程正常結束,那么在主線程中打印出來的將是這個字符串;如果子線程被強制終止,那么在主線程中打印出來的將是線程被取消!。

- ??不是這個啦
- 我是想說,前面好幾次都提到了
線程回收, 你是不是忘了告訴我了 - ?? 不好意思哈,一下子沒忍住就說出來了
四、線程的回收
使用pthread_join函數等待線程結束。該函數需要兩個參數:線程標識符和指向線程返回值的指針。
int pthread_join(pthread_t thread, void **value_ptr);
| 參數 | 類型 | 描述 |
|---|---|---|
thread |
pthread_t |
要等待的線程標識符 |
value_ptr |
void ** |
用于獲取線程的退出狀態的指針,可以為 NULL,表示不關心退出狀態 |
| 返回值 | int |
0 表示成功,非 0 表示失敗,錯誤代碼保存在 errno 中 |
?? 注意:調用 pthread_join() 函數會阻塞當前線程,直到指定的線程終止為止。
如果指定的線程已經終止,那么該函數會立即返回,并且不會阻塞。
另外,線程的退出狀態只有在 pthread_join() 調用成功時才能被獲取,否則 value_ptr 指向的值是未定義的。

如果線程終止后,其它線程沒有調用 pthread_join()函數來回收該線程,這個線程會變成僵尸線程,會浪費系統資源;若僵尸線程積累過多,那么會導致應
用程序無法創建新的線程。

五、線程的分離
可以使用pthread_detach函數將線程分離。pthread_detach函數的原型如下:
int pthread_detach(pthread_t thread);
| 參數 | 類型 | 描述 |
|---|---|---|
| thread | pthread_t | 要分離的線程標識符 |
| 返回值 | int | 0 表示成功,非 0 表示失敗,錯誤代碼保存在 errno 中 |
調用 pthread_detach() 函數將使得指定線程在退出時自動釋放其相關資源,而不需要其他線程調用 pthread_join() 函數來等待它的退出并回收資源。
如果指定的線程已經被分離或者已經退出,那么調用 pthread_detach() 函數將返回一個錯誤。
下面是一個簡單的例子,演示如何使用pthread_detach函數將線程分離:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("這是線程函數,i=%d\n", i);
sleep(1);
}
pthread_exit((void *) "線程正常結束!");
}
int main()
{
pthread_t tid; // 線程標識符
// 創建新線程
if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
printf("線程創建失敗!\n");
return 1;
}
// 分離線程
if (pthread_detach(tid) != 0) {
printf("線程分離失敗!\n");
return 1;
}
printf("線程已經分離,將自動回收資源!\n");
// 程序結束
return 0;
}
上面的示例程序中,我們在創建線程之后立即將線程分離,并打印一條提示信息,告訴用戶線程已經分離,將在退出時自動回收資源。
當運行上面的程序時,可以看到如下輸出:
線程已經分離,將自動回收資源!
這是線程函數,i=0
這是線程函數,i=1
這是線程函數,i=2
這是線程函數,i=3
這是線程函數,i=4
可以看到,程序創建了一個新線程,并立即將它分離。在子線程中,我們打印了5個字符串,每個字符串間隔1秒。
在主線程中,我們打印了一條提示信息,告訴用戶線程已經分離,將在退出時自動回收資源。最后,程序正常結束,沒有調用pthread_join函數。
小結
我們已經介紹了Linux線程的創建、終止、回收、分離等基本操作。
在實際編程中,我們可能還需要使用一些其他的函數和技巧,例如互斥鎖、條件變量、信號量、讀寫鎖等

?? 欲知后事如何,請聽下回分解!
??歡迎各位 ??點贊 ?收藏 ??評論,如有錯誤請留言指正,非常感謝!
以上,如果覺得對你有幫助,點個贊再走吧,這樣@知微之見也有更新下去的動力!
也歡迎私信我,一起交流!

浙公網安備 33010602011771號