Linux 多線程編程實(shí)例

一、多線程 VS 多進(jìn)程
和進(jìn)程相比,線程有很多優(yōu)勢。在Linux系統(tǒng)下,啟動(dòng)一個(gè)新的進(jìn)程必須分配給它獨(dú)立的地址空間,建立眾多的數(shù)據(jù)表來維護(hù)代碼段和數(shù)據(jù)。而運(yùn)行于一個(gè)進(jìn)程中的多個(gè)線程,他們之間使用相同的地址空間。正是這樣,同一進(jìn)程下的線程之間共享數(shù)據(jù)空間,數(shù)據(jù)可以相互使用,并且線程間切換也要更快些,可以更有效的利用CPU。
二、程序設(shè)計(jì)
[注] 頭文件<pthread.h> 編譯時(shí)要加載動(dòng)態(tài)庫 libpthread.a,使用 -lpthread
1、創(chuàng)建線程
2、等待線程
3、關(guān)閉線程
4、退出清除
1、創(chuàng)建線程
int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void), void *arg)
tidp為線程id,是函數(shù)分配的值,所以要傳一個(gè) pthread_t 的地址。
attr線程屬性,通常為空。
start_rtn為線程要執(zhí)行的函數(shù),返回值為空指針,參數(shù)為后面的*arg
若成功則返回0,否則返回出錯(cuò)編號。
例:
#include<stdio.h>
#include<pthread.h></p> <p>void *func1(void *arg){ //原函數(shù)聲明
int i;
for(i=0;i<5;i++){
printf("this is func1! The num is %d\n",*(int*)arg); //將空指針轉(zhuǎn)換為int型指針
sleep(1);
}
}</p> <p>void *func2(int *m){ //自定義類型聲明,也可以定義非指針類型,但是在create時(shí)會有警告,因?yàn)榉堑刂凡⒉荒芨淖儌魅氲闹?br /> int i;
for(i=0;i<5;i++){
printf("this is func2! The num is %d\n",*m);
(*m)++;
sleep(1);
}
}</p> <p>int main(){
pthread_t id1,id2;
int num = 5;
int *p = #
if(pthread_create(&id1,NULL,(void *)func1,(void *)p) != 0){
printf("thread1 create error!\n");
return -1;
}
if(pthread_create(&id2,NULL,(void *)func2,&num) != 0){
printf("thread2 create error!\n");
return -1;
}
pthread_join(id1,NULL); //等待線程結(jié)束
pthread_join(id2,NULL);
printf("Running complete!\n");
return 0;</p> <p>
}
運(yùn)行結(jié)果:
[fsy@localhost process]$ gcc thC.c -o thC -lpthread -g
[fsy@localhost process]$ ./thC
this is func2! The num is 5
this is func1! The num is 6
this is func2! The num is 6
this is func1! The num is 7
this is func2! The num is 7
this is func1! The num is 8
this is func2! The num is 8
this is func1! The num is 9
this is func2! The num is 9
this is func1! The num is 10
Running complete!
[fsy@localhost process]$
2、等待線程
[注]當(dāng)調(diào)用pthread_create函數(shù)時(shí),線程并沒有開始執(zhí)行,主進(jìn)程應(yīng)有等待,比如用sleep,或者用更專業(yè)的函數(shù):pthread_join
int pthread_join(pthread_t tid, void **rval_ptr)
調(diào)用函數(shù)可以阻塞調(diào)用線程,直到指定的線程終止。
tid為等待退出線程的id,rval_ptr為函數(shù)的返回值。是指向指針的指針,可以置空。
例:
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h></p> <p>void *func(int *p){
int *num=(int *)malloc(sizeof(int)); //必須動(dòng)態(tài)創(chuàng)建,原因可以參考我動(dòng)態(tài)分配內(nèi)存的博客
printf("Please input the number: ");
scanf("%d",num);
return (void *)num; //類型是pthread_create的參數(shù)規(guī)定的
}</p> <p>int main(){
pthread_t pth;
void *a;
if(pthread_create(&pth,NULL,(void *)func,NULL) != 0){
printf("create thread error!\n");
return 1;
}
pthread_join(pth,&a); //指向空指針的指針
printf("get the num from the thread, it's %d\n",*(int *)a);
return 0;
}
3、終止線程
線程終止有以下三種方式:
1、線程從函數(shù)中返回
2、線程可以別其他函數(shù)終止
3、線程自己調(diào)用pthread_exit函數(shù)
void pthread_exit(void *rval_ptr)
rval_ptr為線程退出返回值的指針,即函數(shù)返回值。
4、退出清除
void pthread_cleanup_push(void (*rtn)(void*), void *arg)
rtn為清除函數(shù),arg是清除函數(shù)的參數(shù)
void pthread_cleanup_pop(int execute)
當(dāng)execute 非0時(shí)執(zhí)行清除函數(shù)。為0時(shí)不執(zhí)行。
從pthread_cleanup_push的調(diào)用點(diǎn)到pthread_cleanup_pop之間的程序段中,如果有終止進(jìn)程的動(dòng)作,如調(diào)用pthread_exit或異常終止(不包括return),就會執(zhí)行pthread_cleanup_push()所指定的清理函數(shù)。多個(gè)嵌套匹配時(shí),就近匹配。
例:
#include<stdio.h>
#include<pthread.h></p> <p>void *clean(char *argv){
printf("clean is called by %s\n",argv);
return NULL;
}
void *func1(void *argv){
printf("welcome enter the func1!\n");
pthread_cleanup_push((void*)clean,"the first time call!");
pthread_cleanup_push((void*)clean,"the second time call!");
if(argv){
return (void *)1; //第二次運(yùn)行將此句注掉
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(1);
return (void *)0;
}</p> <p>void *func2(void *argv){
sleep(1); //兩個(gè)線程運(yùn)行先后不確定
printf("welcome enter the func2!\n");
pthread_cleanup_push((void*)clean,"the first time call!");
pthread_cleanup_push((void*)clean,"the second time call!");
if(argv){
pthread_exit(NULL);
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return (void *)0;
}</p> <p>
int main(){
pthread_t tid1,tid2;
if(pthread_create(&tid1,NULL,(void *)func1,(void *)1) != 0){
printf("thread1 create error!\n");
return 1;
}</p> <p> if(pthread_create(&tid2,NULL,(void *)func2,(void *)1) != 0){
printf("thread2 create error!\n");
return 1;
}
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
運(yùn)行結(jié)果:
[fsy@localhost process]$ gcc thClean.c -o thclean -lpthread
[fsy@localhost process]$ ./thclean
welcome enter the func1!
welcome enter the func2!
clean is called by the second time call! //此處先2后1
clean is called by the first time call!
[fsy@localhost process]$ vim thClean.c
[fsy@localhost process]$ gcc thClean.c -o thclean -lpthread
[fsy@localhost process]$ ./thclean
welcome enter the func1!
clean is called by the first time call! //second已經(jīng)被pop
welcome enter the func2!
clean is called by the second time call!
clean is called by the first time call!
[fsy@localhost process]$
相關(guān)文章
Fedora Linux 42 穩(wěn)定版發(fā)布: 帶來大量新功能和軟件更新
Fedora 42昨日發(fā)布,這是 Red Hat 贊助開發(fā)的杰出前沿 Linux 發(fā)行版的最新版,包含大量新功能和軟件更新,使其成為 2025 年上半年發(fā)布的一款出色的 Linux 操作系統(tǒng)之一,內(nèi)2025-04-16如何在Linux查看硬盤信息? 查看Linux硬盤大小類型和硬件信息的5種方法
使用Linux系統(tǒng)的過程中,查看和了解硬盤信息是非常重要的工作,尤其是對于系統(tǒng)管理員而言,那么在Linux系統(tǒng)中如何查看硬盤信息?以下是具體內(nèi)容介紹2025-03-12如何在 Linux 中查看 CPU 詳細(xì)信息? 3招輕松查看CPU型號、核心數(shù)和溫度
在日常運(yùn)維工作中,獲取 CPU 信息是系統(tǒng)運(yùn)維管理員常見的工作內(nèi)容,無論是為了性能調(diào)優(yōu)、硬件升級還是僅僅滿足好奇心2025-03-11什么是 Arch Linux? 獨(dú)樹一幟的Arch Linux發(fā)行版分析
Arch Linux是為簡化,優(yōu)化,現(xiàn)代化,實(shí)用主義,用戶中心和多功能性而創(chuàng)建Linux發(fā)行版,究竟是什么讓 Arch 與眾不同?下面我們就來簡要解讀2025-02-19如何在Linux環(huán)境下制作 Win11裝機(jī)U盤?
一直用的linux辦公,想要將筆記本電腦從 Linux 系統(tǒng)切換回 Windows 11,我們可以制作一個(gè)win11裝機(jī)u盤,詳細(xì)如下2025-02-17Rsnapshot怎么用? 基于Rsync的強(qiáng)大Linux備份工具使用指南
Rsnapshot 不僅可以備份本地文件,還能通過 SSH 備份遠(yuǎn)程文件,接下來詳細(xì)介紹如何安裝、配置和使用 Rsnapshot,包括創(chuàng)建每小時(shí)、每天、每周和每月的本地備份,以及如何進(jìn)2025-02-06Linux Kernel 6.13發(fā)布:附更新內(nèi)容及新特性解讀
Linux 內(nèi)核 6.13 正式發(fā)布,新版本引入了惰性搶占支持,簡化內(nèi)核搶占邏輯,通過減少與調(diào)度器相關(guān)的調(diào)用次數(shù),讓內(nèi)核在運(yùn)行時(shí)表現(xiàn)更優(yōu),從而提高效率2025-01-23五大特性引領(lǐng)創(chuàng)新! 深度操作系統(tǒng) deepin 25 Preview預(yù)覽版發(fā)布
今日,深度操作系統(tǒng)正式推出deepin 25 Preview版本,該版本集成了五大核心特性:磐石系統(tǒng)、全新DDE、Treeland窗口合成器、AI For OS以及Distrobox子系統(tǒng)2025-01-18Linux Mint Xia 22.1重磅發(fā)布: 重要更新一覽
Beta 版 Linux Mint“Xia” 22.1 發(fā)布,新版本基于 Ubuntu 24.04,內(nèi)核版本為 Linux 6.8,這次更新帶來了諸多優(yōu)化和改進(jìn),進(jìn)一步鞏固了 Mint 在 Linux 桌面操作系統(tǒng)領(lǐng)域的2025-01-16LinuxMint怎么安裝? Linux Mint22下載安裝圖文教程
Linux Mint22發(fā)布以后,有很多新功能,很多朋友想要下載并安裝,該怎么操作呢?下面我們就來看看詳細(xì)安裝指南2025-01-16