目錄
一 線程說明
①線程與進(jìn)程:
②線程優(yōu)點(diǎn):
③線程缺點(diǎn):
二 線程開發(fā)API概要
三 線程控制流程
① 線程創(chuàng)建(pthread_create)
② 線程退出(pthread_exit)
③ 線程等待(pthread_join)
④ 線程脫離(pthread_detach)
⑤ 線程ID獲取(pthread_self)
四 完整代碼示例
一 線程說明
Linux 實(shí)現(xiàn)線程的機(jī)制非常獨(dú)特。從內(nèi)核的角度來說,它并沒有線程這個(gè)概念。 Linux 把所有的線程都當(dāng)做進(jìn)程來實(shí)現(xiàn)。內(nèi)核并沒有準(zhǔn)備特別的調(diào)度算法或是定義特別的數(shù)據(jù)結(jié)構(gòu)來表示線程。線程只被視為一個(gè)與其他進(jìn)程共享某些資源的輕量級(jí)進(jìn)程。所以在內(nèi)核中,它看起來就像是一個(gè)普通的進(jìn)程(只是線程和其他一些進(jìn)程共享某些資源,如地址空間)
?
①線程與進(jìn)程:
①所有的輕量級(jí)進(jìn)程(線程)都是在進(jìn)程的內(nèi)部運(yùn)行;
②進(jìn)程是資源分配的最小單位,線程是程序執(zhí)行的最小單位;
③進(jìn)程具有獨(dú)立性,可以有部分共享資源(比如:管道,IPC資源);
④線程大部分資源是共享的(例如:代碼、進(jìn)程數(shù)據(jù)、文件描述符、信號(hào)處理方式),可以有部分資源是私有的(例如:PCB、棧、上下文);
★?每個(gè)線程是有自己的獨(dú)立棧,保存線程運(yùn)行時(shí)形成的臨時(shí)數(shù)據(jù);上下文中保存的是CPU調(diào)度時(shí)存放在寄存器中的臨時(shí)數(shù)據(jù)。
線程 | 進(jìn)程 | |
標(biāo)識(shí)符類型 | pthread_t | pid_t |
獲取id | pthread_self() | getpid() |
創(chuàng)建 | pthread_create() | fork() |
?
②線程優(yōu)點(diǎn):
① 創(chuàng)建一個(gè)新線程的代價(jià)要比創(chuàng)建一個(gè)新進(jìn)程小得多;
② 與進(jìn)程之間的切換相比,線程之間的切換需要操作系統(tǒng)做的工作要少很多;
③ 線程占用的資源要比進(jìn)程少很多;
④ 能充分利用多處理器的可并行數(shù)量;
⑥ 在等待慢速I/O操作結(jié)束的同時(shí),程序可執(zhí)行其他的計(jì)算任務(wù);
⑦ 計(jì)算密集型應(yīng)用,為了能在多處理器系統(tǒng)上運(yùn)行,將計(jì)算分解到多個(gè)線程中實(shí)現(xiàn);
⑧ I/O密集型應(yīng)用,為了提高性能,將I/O等待就緒操作重疊。線程可以同時(shí)等待不同的I/O操作;
?
③線程缺點(diǎn):
① 性能損失:一個(gè)很少被外部事件阻塞的計(jì)算密集型線程往往無法與共它線程共享同一個(gè)處理器。如果計(jì)算密集型 線程的數(shù)量比可用的處理器多,那么可能會(huì)有較大的性能損失,這里的性能損失指的是增加了額外的 同步和調(diào)度開銷,而可用的資源不變;
② 健壯性降低:編寫多線程需要更全面更深入的考慮,在一個(gè)多線程程序里,因時(shí)間分配上的細(xì)微偏差或者因共享了 不該共享的變量而造成不良影響的可能性是很大的,換句話說線程之間是缺乏保護(hù)的;
③ 缺乏訪問控制:進(jìn)程是訪問控制的基本粒度,在一個(gè)線程中調(diào)用某些OS函數(shù)會(huì)對(duì)整個(gè)進(jìn)程造成影響;
④ 編程難度提高:編寫與調(diào)試一個(gè)多線程程序比單線程程序困難得多。
二 線程開發(fā)API概要
多線程開發(fā)在 Linux 平臺(tái)上已經(jīng)有成熟的 pthread 庫支持。其涉及的多線程開發(fā)的最基本概念主要包含三點(diǎn):線程,互斥鎖,條件。其中,線程操作又分線程的創(chuàng)建,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是創(chuàng)建,銷毀,加鎖和解鎖。條件操作有 5 種操作:創(chuàng)建,銷毀,觸發(fā),廣播和等待。其他的一些線程擴(kuò)展概念,如信號(hào)燈等,都可以通過上面的三個(gè)基本元素的基本操作封裝出來。詳細(xì)請(qǐng)見下表:
三 線程控制流程
本篇文章先說明線程的創(chuàng)建,等待,退出這三個(gè)API;
-
使用-pthread編譯和鏈接。
① 線程創(chuàng)建(pthread_create)
#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); //返回值:成功返回0,失敗返回錯(cuò)誤編號(hào)
pthread_t *thread:線程ID,由函數(shù)pthread_self()獲取,類似獲取進(jìn)程pid使用getpid()函數(shù);
const pthread_attr_t *attr:用于定制各種不同的線程屬性,暫可以把它設(shè)置為NULL,以創(chuàng)建默認(rèn)屬性的線程;
void *(*start_routine) (void *):線程中執(zhí)行函數(shù)。新創(chuàng)建的線程從start_rtn函數(shù)的地址開始運(yùn)行,該函數(shù)只有一個(gè)無類型指針參數(shù)arg
void *arg:執(zhí)行函數(shù)中中參數(shù)。如果需要向start_rtn函數(shù)傳遞的參數(shù)不止一個(gè),那么需要把這些參數(shù)放到一個(gè)結(jié)構(gòu)體中,然后把這個(gè)結(jié)構(gòu)的地址作為arg參數(shù)傳入
② 線程退出(pthread_exit)
單個(gè)線程可以通過以下三種方式退出,在不終止整個(gè)進(jìn)程的情況下停止它的控制流:
?1)線程只是從啟動(dòng)例程中返回,返回值是線程的退出碼。
?2)線程可以被同一進(jìn)程中的其他線程取消。
?3)線程調(diào)用pthread_exit:
#include <pthread.h> int pthread_exit(void *rval_ptr);
rval_ptr:是一個(gè)無類型指針,與傳給啟動(dòng)例程的單個(gè)參數(shù)類似。進(jìn)程中的其他線程可以通過調(diào)用pthread_join函數(shù)訪問到這個(gè)指針。
③ 線程等待(pthread_join)
#include <pthread.h> int pthread_join(pthread_t thread, void **rval_ptr); // 返回:若成功返回0,否則返回錯(cuò)誤編號(hào)
調(diào)用這個(gè)函數(shù)的線程將一直阻塞,直到指定的線程調(diào)用pthread_exit、從啟動(dòng)例程中返回或者被取消。如果例程只是從它的啟動(dòng)例程返回,rval_ptr將包含返回碼。如果線程被取消,由rval_ptr指定的內(nèi)存單元就置為PTHREAD_CANCELED。①可以通過調(diào)用pthread_join自動(dòng)把線程置于分離狀態(tài),這樣資源就可以恢復(fù)。如果線程已經(jīng)處于分離狀態(tài),pthread_join調(diào)用就會(huì)失敗,返回EINVAL。②如果對(duì)線程的返回值不感興趣,可以把rval_ptr置為NULL。在這種情況下,調(diào)用pthread_join函數(shù)將等待指定的線程終止,但并不獲得線程的終止?fàn)顟B(tài)。
④ 線程脫離(pthread_detach)
一個(gè)線程或者是可匯合(joinable,默認(rèn)值),或者是脫離的(detached)。當(dāng)一個(gè)可匯合的線程終止時(shí),它的線程ID和退出狀態(tài)將留存到另一個(gè)線程對(duì)它調(diào)用pthread_join。脫離的線程卻像守護(hù)進(jìn)程,當(dāng)它們終止時(shí),所有相關(guān)的資源都被釋放,我們不能等待它們終止。如果一個(gè)線程需要知道另一線程什么時(shí)候終止,那就最好保持第二個(gè)線程的可匯合狀態(tài)。
pthread_detach函數(shù)把指定的線程轉(zhuǎn)變?yōu)槊撾x狀態(tài)。
#include <pthread.h> int pthread_detach(pthread_t thread); // 返回:若成功返回0,否則返回錯(cuò)誤編號(hào)
本函數(shù)通常由想讓自己脫離的線程使用,就如以下語句:文章來源:http://www.zghlxwxcb.cn/news/detail-480479.html
pthread_detach(pthread_self());
⑤ 線程ID獲取(pthread_self)
#include <pthread.h>
pthread_t pthread_self(void);
// 返回:調(diào)用線程的ID
四 完整代碼示例
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void *func(void *arg)//定義執(zhí)行函數(shù)func
{
static int ret = 10;//定義tid2線程退出碼
printf("tid2:%lu\n",pthread_self());//
printf("pid2:%d\n",getpid());//進(jìn)程id
pthread_exit((void *)&ret);//結(jié)束線程tid2
}
int main()
{
int *pret;
pthread_t tid1;//定義主線程
pthread_t tid2;//定義子線程
pid_t pid1;//進(jìn)程id
pid_t pid2;//進(jìn)程id
printf("tid1:%lu\n",pthread_self());//打印主線程id
printf("pid1:%d\n",getpid());//打印進(jìn)程id
pthread_create(&tid2,NULL,func,NULL);//創(chuàng)建線程tid2
pthread_join(tid2,(void **)&pret);//等待線程tid2退出,獲取退出狀態(tài)碼
printf("tid2 exit retval:%d\n",*pret);//打印線程退出的狀態(tài)碼
return 0;
}
代碼執(zhí)行結(jié)果:進(jìn)程id一樣,線程id不一樣,說明在同一個(gè)進(jìn)程中執(zhí)行了兩條不同的線程,獲取到已經(jīng)定義好的退出狀態(tài)碼10。文章來源地址http://www.zghlxwxcb.cn/news/detail-480479.html
dhw@dhw-virtual-machine:~/thread$ ./a.out
tid1:140212273063744
pid1:6791
tid2:140212273059392
pid2:6791
tid2 exit retval:10
到了這里,關(guān)于Linux線程:創(chuàng)建(pthread_create),等待(pthread_join),退出(pthread_exit)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!