做網(wǎng)站的圖片新網(wǎng)站百度多久收錄
文章目錄
- 1. 線程分離
- 1. 為什么要線程分離?
- 2. 具體使用
- 3. 為什么有時候分離在調(diào)用join 會正常運(yùn)行?
- 2. 如何理解線程庫?
- 如何理解 先描述 在組織?
- 3. C++中使用多線程
- 4. 線程局部存儲
- 局部變量
- 全局變量
1. 線程分離
1. 為什么要線程分離?
使用 pthread_join 默認(rèn)是阻塞的 ,即主線程等待 新線程退出
在這個過程中,主線程會直接卡住,就沒辦法繼續(xù)向后運(yùn)行,也就什么都干不了
若主線程 想做其他事情 ,所以就提出了線程分離的概念
默認(rèn)情況下,新創(chuàng)建的線程是joinable的
即 線程默認(rèn)被創(chuàng)建出來時,必須被join的, 若不能被join,線程對應(yīng)的資源就無法釋放,進(jìn)而造成內(nèi)存泄漏問題
若不關(guān)心線程的返回值,join是一種負(fù)擔(dān),創(chuàng)建一個線程時,提前告訴它,要分離這個線程
2. 具體使用
輸入 man pthread_detach

參數(shù)為 要分離線程的線程id
一個線程被分離,就無法再被join,如果join,函數(shù)就會報錯


剛開始有主線程和新線程,使用pthread_join 使主線程等待新線程退出
隨著自定義函數(shù)循環(huán)結(jié)束,將返回值傳給join,新線程結(jié)束,
在休眠5秒后,主線程結(jié)束


由于使用線程分離后,就不能使用pthread_join ,所以運(yùn)行可執(zhí)行程序后會報錯
3. 為什么有時候分離在調(diào)用join 會正常運(yùn)行?

在自定義函數(shù)中自己把自己分離

可執(zhí)行程序運(yùn)行后,發(fā)現(xiàn)并沒有報錯,分離和沒分離是一樣的
線程被創(chuàng)建的時候,誰先執(zhí)行并不確定
當(dāng)使用pthread_create 創(chuàng)建線程時,有可能新線程沒有跑,而是主線程繼續(xù)向下執(zhí)行,進(jìn)入join,
然后新線程才把自己分離
join時沒有分離,join后才進(jìn)行分離,所以會正常執(zhí)行程序
2. 如何理解線程庫?

自己形成的可執(zhí)行程序,要跟庫文件關(guān)聯(lián)起來
庫要加載到內(nèi)存中,經(jīng)過頁表映射到地址空間的共享區(qū)中
進(jìn)程中的多線程,可以隨時訪問庫中的代碼和數(shù)據(jù)
每個線程也都可以訪問映射過來的pthread庫
線程庫也需要管理線程,先描述再組織
線程庫創(chuàng)建類似的管理線程的TCB

創(chuàng)建進(jìn)程時,在內(nèi)核中存在LWP(輕量級進(jìn)程),為了更好管理LWP,沒辦法給用提供線程接口,就必須使用pthread庫來適配,對線程做管理,與LWP產(chǎn)生關(guān)聯(lián),包含庫中的線程屬性 即TCB
在庫中通過自己定義的線程控制結(jié)構(gòu),把內(nèi)核中的LWP控制起來
如何理解 先描述 在組織?

描述:
struct pthread 描述的是線程的其他的一些屬性
線程局部存儲 (后面會詳細(xì)講)
線程獨(dú)立的棧
整體紅色的框 作為一個結(jié)構(gòu)體 等同于 線程的TCB 結(jié)構(gòu) 進(jìn)行描述
創(chuàng)建一個線程就有一個紅色框
組織:
整體紅色的框 作為一個結(jié)構(gòu)體
把 每個結(jié)構(gòu)體想象成數(shù)組, 可以聚合在一起
找線程,找紅色框的起始地址即可 稱為 線程ID
pthread_t 就是一個地址數(shù)據(jù),用來標(biāo)識線程相關(guān)屬性集合、
這個地址是虛擬地址
3. C++中使用多線程
添加頭文件 #include < thread>

使用 thread 創(chuàng)建對象th
想要執(zhí)行什么方法,可以把方法傳入對象中
通過對象 . 的方式 可以調(diào)用 join detach 等
c++底層是對原生線程庫的封裝
所以需要在makefile中添加pthread庫

可執(zhí)行程序即可正常運(yùn)行
4. 線程局部存儲

局部變量
局部變量在每個線程中是私有的

cnt在自定義函數(shù)中作為局部變量,屬于棧上的
每個線程都有自己的棧,所以cnt屬于每個線程都有的


三個線程對應(yīng)的cnt地址是不相同的
三個線程的棧是不同的,局部變量cnt開辟到不同的棧中
cnt是同一個變量,地址絕對不一樣
在自定義函數(shù)內(nèi)定義的 局部變量cnt 是在運(yùn)行時開辟的
編譯時就把代碼編譯好了
局部變量會轉(zhuǎn)化為匯編,以棧頂或者棧底為參考點(diǎn) 減去或者加上 對應(yīng)數(shù)字 就代表是開辟空間

更改 ebp 和 esp 就可以切換棧
ebp 可以是 線程1 、線程2、線程3的棧底,根據(jù)調(diào)度的不同 ,在不同的棧中開辟不同的變量
全局變量
默認(rèn)情況下,全局變量是所有線程共享的

創(chuàng)建全局變量g_val,并對其進(jìn)行修改

當(dāng)有多個線程對全局變量修改時,地址是相同的 ,說明全局變量是所有線程共享的

全局變量在已初始化數(shù)據(jù)段處開辟的空間
若不想g_val 被全局共享 ,則加入 __thread 編譯選項
可以構(gòu)建每個線程之間的局部存儲


每個線程對應(yīng)的地址是不一樣的
說明全局變量g_val 在每個線程中各自有一份

修改后的全局變量 在 線程局部存儲 當(dāng)中
將原來的全局變量給 主線程 以及新線程對應(yīng)的 線程局部存儲 都拷貝一份
每個線程都私有一份,所以地址都不一樣