線程創(chuàng)建
?專欄內(nèi)容:
參天引擎內(nèi)核架構(gòu)
本專欄一起來聊聊參天引擎內(nèi)核架構(gòu),以及如何實(shí)現(xiàn)多機(jī)的數(shù)據(jù)庫節(jié)點(diǎn)的多讀多寫,與傳統(tǒng)主備,MPP的區(qū)別,技術(shù)難點(diǎn)的分析,數(shù)據(jù)元數(shù)據(jù)同步,多主節(jié)點(diǎn)的情況下對(duì)故障容災(zāi)的支持。手寫數(shù)據(jù)庫toadb
本專欄主要介紹如何從零開發(fā),開發(fā)的步驟,以及開發(fā)過程中的涉及的原理,遇到的問題等,讓大家能跟上并且可以一起開發(fā),讓每個(gè)需要的人成為參與者。
本專欄會(huì)定期更新,對(duì)應(yīng)的代碼也會(huì)定期更新,每個(gè)階段的代碼會(huì)打上tag,方便階段學(xué)習(xí)。
?開源貢獻(xiàn):
- toadb開源庫
個(gè)人主頁:我的主頁
管理社區(qū):開源數(shù)據(jù)庫
座右銘:天行健,君子以自強(qiáng)不息;地勢坤,君子以厚德載物.
前言
現(xiàn)代的CPU都是多core處理器,而且在intel處理器中每個(gè)core又可以多個(gè)processor,形成了多任務(wù)并行處理的硬件架構(gòu),在服務(wù)器端的處理器上架構(gòu)又有一些不同,傳統(tǒng)的采用SMP,也就是對(duì)稱的多任務(wù)處理架構(gòu),每個(gè)任務(wù)都可以對(duì)等的訪問所有內(nèi)存,外設(shè)等,而如今在ARM系列CPU上,多采用NUMA架構(gòu),它將CPU核分了幾個(gè)組,給每個(gè)組的CPU core分配了對(duì)應(yīng)的內(nèi)存和外設(shè),CPU訪問對(duì)應(yīng)的內(nèi)存和外設(shè)時(shí)速度最優(yōu),跨組訪問時(shí)性能會(huì)降底一些。
隨著硬件技術(shù)的持續(xù)發(fā)展,它們對(duì)一般應(yīng)用的性能優(yōu)化能力越來越強(qiáng),同時(shí)對(duì)于服務(wù)器軟件的開發(fā),提出更高要求,要想達(dá)到極高的并發(fā)和性能,就需要充分利用當(dāng)前硬件架構(gòu)的特點(diǎn),對(duì)它們進(jìn)行壓榨。那么,我們的應(yīng)用至少也是要采用多任務(wù)架構(gòu),不管是多線程還是多進(jìn)程的多任務(wù)架構(gòu),才可以充分利用硬件的資源,達(dá)到高效的處理能力。
當(dāng)然多任務(wù)框架的采用,不僅僅是多線程的執(zhí)行,需要對(duì)多任務(wù)下帶來的問題進(jìn)行處理,如任務(wù)執(zhí)行返回值獲取,任務(wù)間數(shù)據(jù)的傳遞,任務(wù)執(zhí)行次序的協(xié)調(diào);當(dāng)然也不是任務(wù)越多處理越快,要避免線程過多導(dǎo)致操作系統(tǒng)夯住,也要防止任務(wù)空轉(zhuǎn)過快導(dǎo)致CPU使用率飆高。
本專欄主要介紹使用多線程與多進(jìn)程模型,如何搭建多任務(wù)的應(yīng)用框架,同時(shí)對(duì)多任務(wù)下的數(shù)據(jù)通信,數(shù)據(jù)同步,任務(wù)控制,以及CPU core與任務(wù)綁定等相關(guān)知識(shí)的分享,讓大家在實(shí)際開發(fā)中輕松構(gòu)建自已的多任務(wù)程序。
概述
本文主要分享多線程的創(chuàng)建,退出,以及線程屬性的設(shè)置,線程執(zhí)行返回等相關(guān)posix API,以及流程。
在多任務(wù)架構(gòu)搭建中,常常使用多線程方式,因?yàn)榫€程相較于進(jìn)程,是一種輕量級(jí)的任務(wù),也是最小的任務(wù)單元,還有一個(gè)關(guān)鍵點(diǎn)是,線程間的通信方式更加靈活和方便,相反的進(jìn)程間通信就必須要借助內(nèi)核手段。
線程的使用流程,主要包括線程的創(chuàng)建啟動(dòng),線程的退出,線程任務(wù)返回值獲取,線程信息的管理等幾方面。
在linux中我們采用posix線程庫進(jìn)行介紹,在編譯時(shí)需要增加 -lpthread
,頭文件需要包括 # include <pthread.h>
。
線程介紹
我們已經(jīng)知道線程是一種輕量級(jí)的任務(wù)單元,它是在進(jìn)程中創(chuàng)建,共享當(dāng)前進(jìn)程的內(nèi)存上下文,也就是說線程是在進(jìn)程的控制之下,進(jìn)程不存在時(shí),線程也就會(huì)退出,這就是“皮之不存,毛將焉附”。
另外一個(gè)重要特點(diǎn)是,線程的內(nèi)存模型,同一進(jìn)程中的所有線程共享當(dāng)前進(jìn)程的內(nèi)存空間,這就是說不同線程對(duì)全局變量的修改,都是相互可以看到的,動(dòng)態(tài)內(nèi)存申請(qǐng)的內(nèi)存也是可以相互傳遞的,同時(shí)局部靜態(tài)變量也是共享的。
創(chuàng)建線程
在linux 創(chuàng)建線程,需要指定線程的描述符,線程的任務(wù)執(zhí)行函數(shù),以及它的入?yún)?,?dāng)然也可以對(duì)線程的屬性進(jìn)行設(shè)置。
- 創(chuàng)建線程的函數(shù)
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void *),
void *restrict arg);
- 參數(shù)說明
thread
, 線程描述符,記錄線程句標(biāo)識(shí);
attr
, 線程屬性,可以線程行為進(jìn)行控制;
start_routine
, 線程執(zhí)行的主函數(shù);聲明格式為 void * func(void *pointer);
arg
, 主函數(shù)的入?yún)?,因?yàn)橹骱瘮?shù)是由線程調(diào)度程序自動(dòng)調(diào)用的,參數(shù)必須在創(chuàng)建時(shí)指定。
退出線程
線程的退出,可以通過以下幾種方式:
- start_routine 線程執(zhí)行函數(shù)正常返回,如函數(shù)完成時(shí)執(zhí)行return ;
- 調(diào)用線程退出函數(shù) pthread_exit, 這相當(dāng)于執(zhí)行函數(shù)提前退出;
- 使用線程控制函數(shù) pthread_cancel,讓某一線程退出;
- 線程所在的進(jìn)程退出,或者調(diào)用exit,或者主函數(shù)main返回了,這都會(huì)導(dǎo)致該進(jìn)程下的所有線程退出。
獲取返回值
很多時(shí)候,線程執(zhí)行結(jié)束后,都會(huì)帶有返回值,調(diào)用者需要根據(jù)返回值決定任務(wù)執(zhí)行的情況,如何獲取線程執(zhí)行函數(shù)的返回值呢?
同一進(jìn)程下的各線程間的關(guān)系是平等的,只要知道了線程的標(biāo)識(shí)后,調(diào)用下面的函數(shù)就可以獲取對(duì)方的返回值。
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
- 參數(shù)說明
thread
, 線程的標(biāo)識(shí),創(chuàng)建線程時(shí)會(huì)得到;
retval
, 返回碼;由pthread_exit或者return 返回;
- 函數(shù)說明
調(diào)用者調(diào)用此函數(shù)后會(huì)被阻塞,至到thread標(biāo)識(shí)的線程返回為止。
線程信息
線程在創(chuàng)建以后,除了調(diào)用者可以獲取線程標(biāo)識(shí)外,線程本身也可以通過函數(shù)獲取自己的標(biāo)識(shí)。
#include<pthread.h>
pthread_t pthread_self(void)
示例代碼
示例代碼位置
multipleThreads/example_01
threadCreate.c
Makefile
代碼如下:
/*
* created by senllang 2023/12/24
* mail : study@senllang.onaliyun.com
* Copyright (C) 2023-2023, senllang
*/
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void *thread(void *arg)
{
char *ret;
printf("thread() entered with argument '%s'\n", arg);
if ((ret = (char*) malloc(20)) == NULL)
{
perror("malloc() error");
exit(2);
}
strcpy(ret, "This is a test");
pthread_exit(ret);
}
int main(int argc, char *argv[])
{
pthread_t thid;
void *ret;
if (pthread_create(&thid, NULL, thread, "thread 1") != 0)
{
perror("pthread_create() error");
exit(1);
}
if (pthread_join(thid, &ret) != 0)
{
perror("pthread_create() error");
exit(3);
}
printf("thread exited with '%s'\n", ret);
}
編譯時(shí),需要在加上線程庫 lpthread ,運(yùn)行結(jié)果如下:
[senllang@hatch example_01]$ ll
total 8
-rw-r--r--. 1 senllang develops 1265 Dec 24 20:32 Makefile
-rw-r--r--. 1 senllang develops 781 Dec 24 20:33 threadCreate.c
[senllang@hatch example_01]$ make
gcc -I./ -DTEST_PRO -lpthread -g -c threadCreate.c
gcc -I./ -DTEST_PRO -lpthread -g *.o -o hatch-0-01
[senllang@hatch example_01]$ ll
total 40
-rwxr-xr-x. 1 senllang develops 21368 Dec 24 20:34 hatch-0-01
-rw-r--r--. 1 senllang develops 1265 Dec 24 20:32 Makefile
-rw-r--r--. 1 senllang develops 781 Dec 24 20:33 threadCreate.c
-rw-r--r--. 1 senllang develops 7600 Dec 24 20:34 threadCreate.o
[senllang@hatch example_01]$ ./hatch-0-01
thread() entered with argument 'thread 1'
thread exited with 'This is a test'
總結(jié)
本文重點(diǎn)分享了線程的創(chuàng)建使用,在main中需要等待線程的結(jié)束,因?yàn)樗钱?dāng)前進(jìn)程的主線程,如果它提前結(jié)束,由它創(chuàng)建的所有線程也會(huì)提前結(jié)束,所以它需要等待所有線程結(jié)束之后,才能退出。
后面會(huì)繼續(xù)介紹更多線程的知識(shí),完成一個(gè)通用線程池的功能。
所有示例的代碼已經(jīng)上傳到gitcode上的工程hatchCode,大家有興趣的可以點(diǎn)star進(jìn)行關(guān)注。
結(jié)尾
非常感謝大家的支持,在瀏覽的同時(shí)別忘了留下您寶貴的評(píng)論,如果覺得值得鼓勵(lì),請(qǐng)點(diǎn)贊,收藏,我會(huì)更加努力!文章來源:http://www.zghlxwxcb.cn/news/detail-761375.html
作者郵箱:study@senllang.onaliyun.com
如有錯(cuò)誤或者疏漏歡迎指出,互相學(xué)習(xí)。文章來源地址http://www.zghlxwxcb.cn/news/detail-761375.html
到了這里,關(guān)于【linux c多線程】線程的創(chuàng)建,線程信息的獲取,獲取線程返回值的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!