概述
線程是輕量級的進程(LWP:light weight process),在 Linux 環(huán)境下線程的本質(zhì)仍是進程。在計算機上運行的程序是一組指令及指令參數(shù)的組合,指令按照既定的邏輯控制計算機運行。操作系統(tǒng)會以進程為單位,分配系統(tǒng)資源,可以這樣理解,進程是資源分配的最小單位,線程是操作系統(tǒng)調(diào)度執(zhí)行的最小單位。
在Linux系統(tǒng)下,線程的創(chuàng)建和管理是通過pthread庫實現(xiàn)的。pthread是POSIX線程庫,提供了創(chuàng)建、終止、同步和通信線程的函數(shù)和數(shù)據(jù)結(jié)構(gòu)。
創(chuàng)建線程
線程函數(shù)
每一個線程都有一個唯一的線程 ID,ID 類型為 pthread_t,這個 ID 是一個無符號長整形數(shù),如果想要得到當前線程的線程 ID,可以調(diào)用如下函數(shù):
pthread_t pthread_self(void); // 返回當前線程的線程ID
在Linux系統(tǒng)下,可以使用pthread_create函數(shù)來創(chuàng)建線程。pthread_create函數(shù)的原型如下:
#include <pthread.h>
int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);
- thread:指向pthread_t類型的指針,用于存儲新創(chuàng)建線程的標識符。在成功創(chuàng)建線程后,該指針將被填充為一個唯一的標識符,用于后續(xù)對線程的引用。
- attr:指向pthread_attr_t類型的指針,用于指定線程的屬性。線程屬性對象可以控制線程的各種行為,例如線程的調(diào)度策略、棧大小、分離狀態(tài)等。如果不需要對線程屬性進行特殊設置,可以傳入NULL,使用默認屬性。
- start_routine:指向線程函數(shù)的指針,該函數(shù)是線程的入口點。線程函數(shù)是線程的實際執(zhí)行體,當線程被創(chuàng)建時,將從該函數(shù)開始執(zhí)行。函數(shù)的返回類型必須為void*,并接受一個void*類型的參數(shù)。線程函數(shù)可以執(zhí)行任意操作,包括計算、訪問共享資源等。
- arg:傳遞給線程函數(shù)的參數(shù),類型為void*??梢詫⑷我忸愋偷臄?shù)據(jù)傳遞給線程函數(shù),只需將其轉(zhuǎn)換為void*類型。在線程函數(shù)內(nèi)部,可以使用適當?shù)念愋娃D(zhuǎn)換將參數(shù)恢復為原始類型。
返回值:線程創(chuàng)建成功返回 0,創(chuàng)建失敗返回對應的錯誤號
在編寫多線程程序的時候,如果想要讓線程退出,但是不會導致虛擬地址空間的釋放(針對于主線程),我們就可以調(diào)用線程庫中的線程退出函數(shù),只要調(diào)用該函數(shù)當前線程就馬上退出了,并且不會影響到其他線程的正常運行,不管是在子線程或者主線程中都可以使用。
void pthread_exit(void *retval);
參數(shù) retval 是一個指向任意類型的指針,表示線程的退出狀態(tài)。線程的退出狀態(tài)可以用于與其他線程進行通信或傳遞結(jié)果。
pthread_self() 是一個 POSIX 線程庫函數(shù),用于獲取當前線程的線程 ID。
pthread_t pthread_self(void);
線程創(chuàng)建
注意:線程函數(shù)可以接受一個指向任意類型的參數(shù),并且返回一個指向任意類型的指針。
首先使用vim pthread_create.c
創(chuàng)建c語言文件。
鍵入代碼:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *callback(void* arg)
{
for(int i=0;i<5;++i)
{
printf("子線程:i=%d\n",i);
}
printf("子線程:%ld\n",pthread_self());
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,callback,NULL);
for(int i=0;i<5;++i)
{
printf("主線程:i=%d\n",i);
}
printf("主線程:%ld\n",pthread_self());
pthread_exit(NULL);
return 0;
}
保存文件后使用g++ pthread_create.c -lpthread -o app
命令進行編譯。
該命令用于編譯名為 pthread_create.c 的源代碼文件,并鏈接 pthread 庫生成可執(zhí)行文件 app。
g++:是 GNU 編譯器集合中的 C++ 編譯器。
pthread_create.c:是要編譯的源代碼文件的名稱。
-lpthread:表示鏈接 pthread 庫,這是 POSIX 線程庫。
-o app2:指定生成的可執(zhí)行文件的名稱為 app2
執(zhí)行./app
,結(jié)果如下所示
線程回收
在線程編程中,線程回收是指等待線程執(zhí)行結(jié)束并收回相關資源。在 POSIX 線程庫中,可以使用 pthread_join 函數(shù)來實現(xiàn)線程的回收。pthread_join 函數(shù)的原型如下:
int pthread_join(pthread_t thread, void **retval);
其中,thread 參數(shù)是要回收的線程標識符,retval參數(shù)用于接收線程的返回值。函數(shù)的返回值表示回收線程的執(zhí)行狀態(tài),如果成功回收線程,則返回 0,否則返回一個非零值,表示出現(xiàn)了錯誤。
當調(diào)用 pthread_join 函數(shù)時,當前線程會被阻塞,直到指定的線程執(zhí)行結(jié)束。一旦線程執(zhí)行結(jié)束,它的資源將被回收,并可以通過 retval 參數(shù)獲取線程的返回值。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
struct persion
{
int num;
int age;
};
void *callback(void* arg)
{
for(int i=0;i<5;++i)
{
printf("子線程:i=%d\n",i);
}
printf("子線程:%ld\n",pthread_self());
struct persion* t = (struct persion*)arg;
t->num=100;
t->age=5;
pthread_exit(&t);
return NULL;
}
int main()
{
pthread_t tid;
struct persion t;
pthread_create(&tid,NULL,callback,&t);
for(int i=0;i<5;++i)
{
printf("主線程:i=%d\n",i);
}
printf("主線程:%ld\n",pthread_self());
void *ptr;
pthread_join(tid,&ptr);
struct persion *pt=(struct persion*)ptr;
printf("num:%d,age:%d\n",t.num,t.age);
pthread_exit(NULL);
return 0;
}
pthread_join其實是個阻塞函數(shù),如果還有子線程在運行,調(diào)用該函數(shù)就會阻塞,子線程退出函數(shù)解除阻塞進行資源的回收,函數(shù)被調(diào)用一次,只能回收一個子線程,如果有多個子線程則需要循環(huán)進行回收。
ptr 用于接收子線程的返回值,pt 通過強制類型轉(zhuǎn)換指向子線程的返回值,而 t 是主線程中的一個獨立對象
結(jié)果如下所示:
線程分離
線程的分離是指將線程設置為分離狀態(tài),使其在退出時自動釋放資源,不需要顯式地調(diào)用 pthread_join 函數(shù)來等待線程的結(jié)束。
在某些情況下,程序中的主線程有屬于自己的業(yè)務處理流程,如果讓主線程負責子線程的資源回收,調(diào)用 pthread_join() 只要子線程不退出主線程就會一直被阻塞,主要線程的任務也就不能被執(zhí)行了。
線程分離之后在主線程中使用 pthread_join() 就回收不到子線程資源了。文章來源:http://www.zghlxwxcb.cn/news/detail-494379.html
for(int i=0;i<5;++i)
{
printf("子線程:i=%d\n",i);
}
printf("子線程:%ld\n",pthread_self());
struct persion* t = (struct persion*)arg;
t->num=100;
t->age=5;
pthread_exit(&t);
return NULL;
}
int main()
{
pthread_t tid;
struct persion t;
pthread_create(&tid,NULL,callback,&t);
for(int i=0;i<5;++i)
{
printf("主線程:i=%d\n",i);
}
printf("主線程:%ld\n",pthread_self());
pthread_detach(tid);
pthread_exit(NULL);
return 0;
}
線程分離后,子線程執(zhí)行完畢后被系統(tǒng)內(nèi)核回收了,且主線程退出后不會影響子線程的執(zhí)行。文章來源地址http://www.zghlxwxcb.cn/news/detail-494379.html
到了這里,關于【Linux】C語言中多線程的創(chuàng)建、退出、回收、分離的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!