本文參考了 用戶態(tài)非搶占式線程庫實現(xiàn) 一文以及 GNU Pth 。前者是一種用戶態(tài)線程庫的簡單實現(xiàn),屬于一個很好的demo,后者就是大家熟知的Pthread的用戶態(tài)實現(xiàn),比較完善。
Keywords: User-Space MultiThreading, Pth
所謂多線程,簡單講就是能夠讓幾個不同的代碼片段輪流執(zhí)行。內(nèi)核實現(xiàn)多線程的方法比較直觀,在每次時鐘中斷到來時或者用戶調(diào)用syscall陷入內(nèi)核時進行上下文切換即可。用戶態(tài)切換線程要解決兩個問題:
1、時機,即何時切換線程?
2、方法,即怎樣切換上下文?
為了決定切換時機,需要確定所設計的線程庫是可剝奪(preemptive)的還是不可剝奪(non-preemptive)的。一般,用戶態(tài)線程庫都選擇使用不可剝奪的設計方案,這么做的好處是將控制權(quán)交給用戶,而用戶最了解何時需要放棄執(zhí)行權(quán)。這么做減少了系統(tǒng)切換次數(shù),實現(xiàn)了最高的CPU利用率,非常適合用于科學計算環(huán)境。但是,另一方面這么做也存在缺點:其它線程的響應速度變慢,他們必須等到當前CPU放棄執(zhí)行權(quán)后才能被執(zhí)行。能不能將用戶線程設計成可剝奪的呢?這應該也是可行的。每個用戶線程運行一段時間后會被迫暫停執(zhí)行,被動地將控制權(quán)交回給調(diào)度器。怎樣才能“被迫暫停執(zhí)行”?這是方法問題,下面就要講到。
對于不可剝奪方式,需要用戶編寫程序的時候主動調(diào)用諸如thread_yeild(), thread_wai()之類的函數(shù),這些函數(shù)會將當前用戶線程的執(zhí)行上下文保存起來,然后讓調(diào)度器選擇一個新的用戶線程投入執(zhí)行。底層操作系統(tǒng)提供了一些列的機制支持上下文的獲得和切換,如setjmp,longjmp,getcontext,swapcontext等。 用戶態(tài)非搶占式線程庫實現(xiàn) 一文使用了前面兩個函數(shù), GNU Pth 使用了后面兩個函數(shù)??蓜儕Z方式的實現(xiàn)需要更多的操作系統(tǒng)支持,如可以利用alarm函數(shù)周期性地產(chǎn)生用戶態(tài)中斷,每次中斷到來的時候線程庫進行線程切換。
單純的用戶態(tài)線程庫一般都是基于一個單線程進程實現(xiàn)的,一旦用戶線程阻塞,這個進程就被阻塞,進而導致整個用戶態(tài)線程組得不到CPU。基于單進程實現(xiàn)的用戶態(tài)線程庫在SMP/多CPU環(huán)境下性能很差,多出來的核無法被線程庫利用,這跟當前的微處理器架構(gòu)發(fā)展趨勢十分不符。為了解決這個問題,可以考慮使用一種混合結(jié)構(gòu):在少量內(nèi)核線程的基礎上實現(xiàn)大量的用戶線程。
最后思考一個問題:為什么用戶態(tài)線程庫比內(nèi)核態(tài)線程庫具有更高的性能呢?其實用戶態(tài)線程庫同樣離不開進入內(nèi)核態(tài)這一過程,以getcontext,swapcontex實現(xiàn)方式為例,getcontext要進出一次內(nèi)核,swapcontex又要進出一次內(nèi)核,而內(nèi)核線程切換則只需要一次時鐘中斷,只進出內(nèi)核一次即可。這么說來,用戶態(tài)線程庫的性能應該劣于內(nèi)核態(tài)線程庫。但是,注意到每次時鐘中斷所做的工作遠遠不止上下文切換這么簡單,這應該是用戶態(tài)線程庫更優(yōu)的原因吧?;谶@個分析,如果應用需要創(chuàng)建的線程數(shù)并不多,二者應該性能相當。但是,一旦線程數(shù)巨大且切換頻繁,用戶態(tài)線程庫的優(yōu)勢就能體現(xiàn)出來了。
更多文章、技術(shù)交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
