訂閱
糾錯(cuò)
加入自媒體

一文搞懂多線程中各個(gè)難點(diǎn)

1.什么是線程?

linux內(nèi)核中是沒(méi)有線程這個(gè)概念的,而是輕量級(jí)進(jìn)程的概念:LWP。一般我們所說(shuō)的線程概念是C庫(kù)當(dāng)中的概念。

1.1線程是怎樣描述的?

線程實(shí)際上也是一個(gè)task_struct,工作線程拷貝主線程的task_struct,然后共用主線程的mm_struct。線程ID是在用task_struct中pid描述的,而task_struct中tgid是線程組ID,表示線程屬于該線程組,對(duì)于主線程而言,其pid和tgid是相同的,我們一般看到的進(jìn)程ID就是tgid。

即:

獲取線程ID和主線程ID的值:

但是獲取該gettid系統(tǒng)調(diào)用接口并沒(méi)有被封裝起來(lái),如果確實(shí)需要獲取線程ID,可使用:

#include

則對(duì)線程組而言,所有的tgid一定是一樣的,所有的pid一定是不一樣的。主線程pid和tgid一樣,工作線程pid和tgid一定不一樣。

1.2如何查看一個(gè)線程的ID

命令:ps -eLf

上述polkitd進(jìn)程是多線程的,進(jìn)程ID為731,進(jìn)程內(nèi)有6個(gè)線程,線程ID為731,764,765,768,781,791。

1.3多線程如何避免調(diào)用;靵y的問(wèn)題?

工作線程和主線程共用一個(gè)mm_struct,如果都向棧中壓棧,必然會(huì)導(dǎo)致調(diào)用棧出錯(cuò)。

實(shí)際上工作線程壓棧是壓了共享區(qū),該共享區(qū)包含了許多線程獨(dú)有的資源。如圖:

每一個(gè)線程,默認(rèn)在共享區(qū)中占有的空間為8M,可以使用ulimit -s修改。

進(jìn)程是資源分配的基本單位,線程是調(diào)度的基本單位。

1.3.1線程獨(dú)有資源

線程ID

一組寄存器

errno

信號(hào)屏蔽字

調(diào)度優(yōu)先級(jí)

1.3.2線程共享資源和環(huán)境

文件描述符表

信號(hào)的處理方式

當(dāng)前工作目錄

用戶id和組id

1.4為什么要有多線程?

舉個(gè)生活中的例子, 這就好比去銀行辦理業(yè)務(wù)。到達(dá)銀行后, 首先取一個(gè)號(hào)碼, 然后坐下來(lái)安心等待。這時(shí)候你一定希望, 辦理業(yè)務(wù)的窗口越多越好。如果把整個(gè)營(yíng)業(yè)大廳當(dāng)成一個(gè)進(jìn)程的話, 那么每一個(gè)窗口就是一個(gè)工作線程。

1.4.1線程帶來(lái)的優(yōu)勢(shì)

1、線程會(huì)共享內(nèi)存地址空間。

2、創(chuàng)建線程花費(fèi)的時(shí)間要少于創(chuàng)建進(jìn)程花費(fèi)的時(shí)間。

3、終止線程花費(fèi)的時(shí)間要少于終止進(jìn)程花費(fèi)的時(shí)間。

4、線程之間上下文切換的開(kāi)銷(xiāo), 要小于進(jìn)程之間的上下文切換。

5、線程之間數(shù)據(jù)的共享比進(jìn)程之間的共享要簡(jiǎn)單。

6、充分利用多處理器的可并行數(shù)量。(線程會(huì)提高運(yùn)行效率,但當(dāng)線程多到一定程度后,可能會(huì)導(dǎo)致效率下降,因?yàn)闀?huì)有線程調(diào)度切換。)

1.4.2線程帶來(lái)的缺點(diǎn)

健壯性降低:多個(gè)線程之中, 只要有一個(gè)線程不夠健壯存在bug(如訪問(wèn)了非法地址引發(fā)的段錯(cuò)誤) , 就會(huì)導(dǎo)致進(jìn)程內(nèi)的所有線程一起完蛋。

線程模型作為一種并發(fā)的編程模型, 效率并沒(méi)有想象的那么高, 會(huì)出現(xiàn)復(fù)雜度高、 易出錯(cuò)、 難以測(cè)試和定位的問(wèn)題。

1.5注意

1、并不是只有主線程才能創(chuàng)建線程, 被創(chuàng)建出來(lái)的線程同樣可以創(chuàng)建線程。

2、不存在類(lèi)似于fork函數(shù)那樣的父子關(guān)系, 大家都?xì)w屬于同一個(gè)線程組, 進(jìn)程ID都相等, group_leader都指向主線程, 而且各有各的線程ID。

通過(guò)group_leader指針, 每個(gè)線程都能找到主線程。主線程存在一個(gè)鏈表頭,后面創(chuàng)建的每一個(gè)線程都會(huì)鏈入到該雙向鏈表中。

3、并非只有主線程才能調(diào)用pthread_join連接其他線程, 同一線程組內(nèi)的任意線程都可以對(duì)某線程執(zhí)行pthread_join函數(shù)。

4、并非只有主線程才能調(diào)用pthread_detach函數(shù), 其實(shí)任意線程都可以對(duì)同一線程組內(nèi)的線程執(zhí)行分離操作。

線程的對(duì)等關(guān)系:

2.線程創(chuàng)建

接口:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

參數(shù)解釋

1、thread:線程標(biāo)識(shí)符,是一個(gè)出參

2、attr:線程屬性

3、star_routine:函數(shù)指針,保存線程入口函數(shù)的地址

4、arg:給線程入口函數(shù)傳參

返回值:成功返回0,失敗返回error number

詳解:

第一個(gè)參數(shù)是pthread_t類(lèi)型的指針, 線程創(chuàng)建成功的話,會(huì)將分配的線程ID填入該指針指向的地址。線程的后續(xù)操作將使用該值作為線程的唯一標(biāo)識(shí)。

第二個(gè)參數(shù)是pthread_attr_t類(lèi)型, 通過(guò)該參數(shù)可以定制線程的屬性, 比如可以指定新建線程棧的大小、 調(diào)度策略等。如果創(chuàng)建線程無(wú)特殊的要求, 該值也可以是NULL, 表示采用默認(rèn)屬性。

第三個(gè)參數(shù)是線程需要執(zhí)行的函數(shù)。創(chuàng)建線程, 是為了讓線程執(zhí)行一定的任務(wù)。線程創(chuàng)建成功之后, 該線程就會(huì)執(zhí)行start_routine函數(shù), 該函數(shù)之于線程, 就如同main函數(shù)之于主線程。

第四個(gè)參數(shù)是新建線程執(zhí)行的start_routine函數(shù)的入?yún)ⅰ?/p>

pthread_create錯(cuò)誤碼及描述:

2.1傳入?yún)?shù)arg的選擇

不要使用臨時(shí)變量傳參,使用堆上開(kāi)辟的變量可以。

例:

#include

線程獲取自身的ID:

#include

判斷兩個(gè)線程ID是否對(duì)應(yīng)著同一個(gè)線程:

#include

返回為0時(shí),則表示兩個(gè)線程為同一個(gè)線程,非0時(shí),表示不是同一個(gè)線程。

用戶調(diào)用pthread_create函數(shù)時(shí), 首先要為線程分配線程棧, 而線程棧的位置就落在共享區(qū)。調(diào)用mmap函數(shù)為線程分配?臻g。pthread_create函數(shù)分配的pthread_t類(lèi)型的線程ID, 不過(guò)是分配出來(lái)的空間里的一個(gè)地址, 更確切地說(shuō)是一個(gè)結(jié)構(gòu)體的指針。

即:

1  2  3  4  下一頁(yè)>  
聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)