第五講 Linux多線程_第1頁
第五講 Linux多線程_第2頁
第五講 Linux多線程_第3頁
第五講 Linux多線程_第4頁
第五講 Linux多線程_第5頁
已閱讀5頁,還剩60頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、Linux多線程李杰聰世界不是串行的世界不是串行的真實(shí)世界中很多事情都是同時(shí)發(fā)生的,而不是按次真實(shí)世界中很多事情都是同時(shí)發(fā)生的,而不是按次序發(fā)生。序發(fā)生。隨著軟硬件的發(fā)展計(jì)算機(jī)也進(jìn)入了并行時(shí)代。隨著軟硬件的發(fā)展計(jì)算機(jī)也進(jìn)入了并行時(shí)代。程序員也應(yīng)該做好并行程序設(shè)計(jì)的準(zhǔn)備。程序員也應(yīng)該做好并行程序設(shè)計(jì)的準(zhǔn)備。處理器發(fā)展歷史回顧處理器發(fā)展歷史回顧90年代年代增大指令的并行發(fā)射能力,超標(biāo)量處增大指令的并行發(fā)射能力,超標(biāo)量處理器。理器。90年代末期至年代末期至21世紀(jì)初世紀(jì)初提高主頻提高主頻21世紀(jì)世紀(jì)超線程,多核技術(shù)出現(xiàn),主頻不再?zèng)Q超線程,多核技術(shù)出現(xiàn),主頻不再?zèng)Q定定CPU性能。性能。處理器種類處理器

2、種類通用處理器:通用處理器:intel, amd生產(chǎn)。生產(chǎn)。網(wǎng)絡(luò)處理器:摩托羅拉,網(wǎng)絡(luò)處理器:摩托羅拉, powerpc ,cavium嵌入式處理器:嵌入式處理器:TI(高通),(高通),ARM圖像處理器:圖像處理器:nvida銀行卡銀行卡主卡副卡POSPOS賬戶(¥100)銀行卡銀行卡POS1POS2if (account=100) account=account-100; return 交易成功 else return 余額不夠 刷¥100刷¥100 正確執(zhí)行(賬戶歸零)正確執(zhí)行(賬戶歸零)Pos1 Pos1 Pos2 Pos2 Pos1 錯(cuò)誤執(zhí)行(賬戶透支)錯(cuò)誤執(zhí)行(賬戶透支)Pos1

3、Pos2 Pos2 Pos2 Pos1 Pos1 時(shí)間并發(fā)的幾個(gè)概念并發(fā)的幾個(gè)概念競爭(競爭(race condition):程序執(zhí)行的結(jié)果或者輸程序執(zhí)行的結(jié)果或者輸出取決于某一段代碼的執(zhí)行次序,次序不同結(jié)果不出取決于某一段代碼的執(zhí)行次序,次序不同結(jié)果不同。同。競爭是不確定的,偶發(fā)性較強(qiáng)。競爭是不確定的,偶發(fā)性較強(qiáng)。導(dǎo)致系統(tǒng)異常,數(shù)據(jù)被破壞。導(dǎo)致系統(tǒng)異常,數(shù)據(jù)被破壞。難以重現(xiàn),調(diào)試,發(fā)現(xiàn)競爭。難以重現(xiàn),調(diào)試,發(fā)現(xiàn)競爭。加入調(diào)試代碼時(shí),競爭會(huì)消失?!加入調(diào)試代碼時(shí),競爭會(huì)消失?!銀行卡存在數(shù)據(jù)競爭。銀行卡存在數(shù)據(jù)競爭。并發(fā)的幾個(gè)概念并發(fā)的幾個(gè)概念原子性(原子性(atomic):是系統(tǒng)中最小的一個(gè)

4、操作集合。是系統(tǒng)中最小的一個(gè)操作集合。銀行卡例子中,更新賬戶余額的操作集合需要時(shí)一銀行卡例子中,更新賬戶余額的操作集合需要時(shí)一個(gè)原子操作。也即個(gè)原子操作。也即 是一個(gè)原子操作,否則引是一個(gè)原子操作,否則引入競爭。導(dǎo)致程序運(yùn)行結(jié)果不確定。入競爭。導(dǎo)致程序運(yùn)行結(jié)果不確定。也可把也可把 作為原子操作,但會(huì)降低程序性作為原子操作,但會(huì)降低程序性能。能。對競爭的判斷同時(shí)也是對原子操作范圍的界定。對競爭的判斷同時(shí)也是對原子操作范圍的界定。程序設(shè)計(jì)中,競爭區(qū)域判斷比想象中要困難很多。程序設(shè)計(jì)中,競爭區(qū)域判斷比想象中要困難很多。哲學(xué)家問題哲學(xué)家問題有有5個(gè)哲學(xué)家圍坐在一張圓桌上。個(gè)哲學(xué)家圍坐在一張圓桌上。每相

5、鄰兩個(gè)哲學(xué)家之間有一只筷每相鄰兩個(gè)哲學(xué)家之間有一只筷子。子。哲學(xué)家除了思考就是吃。哲學(xué)家除了思考就是吃。當(dāng)哲學(xué)家餓時(shí),他就先拿起作手當(dāng)哲學(xué)家餓時(shí),他就先拿起作手邊的筷子然后再拿右手邊的筷子邊的筷子然后再拿右手邊的筷子 。當(dāng)有兩只筷子時(shí),哲學(xué)家開始吃當(dāng)有兩只筷子時(shí),哲學(xué)家開始吃飯,否則一直等待另外一只筷子。飯,否則一直等待另外一只筷子。哲學(xué)家吃晚飯后,放下筷子,繼哲學(xué)家吃晚飯后,放下筷子,繼續(xù)思考。續(xù)思考。并發(fā)中的問題并發(fā)中的問題死鎖死鎖 (deadlock):兩個(gè)或者以上的線程互相):兩個(gè)或者以上的線程互相等待,導(dǎo)致整個(gè)系統(tǒng)無法向前推進(jìn)。等待,導(dǎo)致整個(gè)系統(tǒng)無法向前推進(jìn)。例如:例如:5個(gè)哲學(xué)家同

6、時(shí)拿起自己左手邊的筷子,然個(gè)哲學(xué)家同時(shí)拿起自己左手邊的筷子,然后等待右手邊的筷子。由于所有筷子均被占有,導(dǎo)后等待右手邊的筷子。由于所有筷子均被占有,導(dǎo)致沒有一個(gè)哲學(xué)家能進(jìn)食。致沒有一個(gè)哲學(xué)家能進(jìn)食。并發(fā)中的問題并發(fā)中的問題活鎖(活鎖(livelock):兩個(gè)或者以上的線程會(huì)不斷):兩個(gè)或者以上的線程會(huì)不斷的執(zhí)行,不斷的改變狀態(tài),但整個(gè)系統(tǒng)卻不朝著最的執(zhí)行,不斷的改變狀態(tài),但整個(gè)系統(tǒng)卻不朝著最終目的前進(jìn)。終目的前進(jìn)?;铈i一般為了解決死鎖引入的。死鎖的線程只會(huì)等活鎖一般為了解決死鎖引入的。死鎖的線程只會(huì)等待,不會(huì)改變狀態(tài)?;铈i會(huì)改變執(zhí)行狀態(tài),但不會(huì)待,不會(huì)改變狀態(tài)?;铈i會(huì)改變執(zhí)行狀態(tài),但不會(huì)朝著最

7、終目標(biāo)前進(jìn)。朝著最終目標(biāo)前進(jìn)。為了解決哲學(xué)家的死鎖問題。我們規(guī)定:如果哲學(xué)為了解決哲學(xué)家的死鎖問題。我們規(guī)定:如果哲學(xué)家無法拿到右手邊的筷子,那么他必須放下他左手家無法拿到右手邊的筷子,那么他必須放下他左手邊的筷子。等待一會(huì)兒再去嘗試拿筷子。邊的筷子。等待一會(huì)兒再去嘗試拿筷子。舉例:舉例:5個(gè)哲學(xué)同時(shí)拿起左手邊筷子,個(gè)哲學(xué)同時(shí)拿起左手邊筷子, 發(fā)現(xiàn)右手邊發(fā)現(xiàn)右手邊的筷子沒有,又同時(shí)放下左手上的筷子,如此往復(fù)的筷子沒有,又同時(shí)放下左手上的筷子,如此往復(fù)并發(fā)中的問題并發(fā)中的問題饑餓、餓死(饑餓、餓死(starvation):某些線程永遠(yuǎn)無法得某些線程永遠(yuǎn)無法得到執(zhí)行的機(jī)會(huì)。到執(zhí)行的機(jī)會(huì)。舉例:某一

8、哲學(xué)家,每次去拿筷子時(shí),左手或者右舉例:某一哲學(xué)家,每次去拿筷子時(shí),左手或者右手邊的筷子被拿走,該哲學(xué)家只能一直手邊的筷子被拿走,該哲學(xué)家只能一直“餓肚子餓肚子”。公平性(公平性(fairness):有些線程得到的執(zhí)行機(jī)會(huì)):有些線程得到的執(zhí)行機(jī)會(huì)多,多, 有些線程得到的執(zhí)行機(jī)會(huì)少。有些線程得到的執(zhí)行機(jī)會(huì)少。舉例:哲學(xué)家在拿筷子時(shí),有些哲學(xué)家拿到筷子的舉例:哲學(xué)家在拿筷子時(shí),有些哲學(xué)家拿到筷子的可能性可能比其它哲學(xué)家大。比如那些好吃懶做,可能性可能比其它哲學(xué)家大。比如那些好吃懶做,整天嘗試去拿筷子的哲學(xué)家。整天嘗試去拿筷子的哲學(xué)家。多線程概念多線程概念 進(jìn)程是資源分配的對象,時(shí)間片內(nèi)存等。進(jìn)程

9、是資源分配的對象,時(shí)間片內(nèi)存等。 線程是使用資源的實(shí)體,一個(gè)進(jìn)程中的多個(gè)線程共享內(nèi)存,全局變量,線程是使用資源的實(shí)體,一個(gè)進(jìn)程中的多個(gè)線程共享內(nèi)存,全局變量, 文件文件描述符等。描述符等。 線程有獨(dú)立的棧和寄存器線程有獨(dú)立的棧和寄存器線程的優(yōu)缺點(diǎn)線程的優(yōu)缺點(diǎn)優(yōu)點(diǎn):優(yōu)點(diǎn): 上下文切換快上下文切換快 共享數(shù)據(jù)容易共享數(shù)據(jù)容易 創(chuàng)建線程速度快創(chuàng)建線程速度快缺點(diǎn)缺點(diǎn) 內(nèi)存共享會(huì)導(dǎo)致互相干擾內(nèi)存共享會(huì)導(dǎo)致互相干擾 一個(gè)線程崩潰會(huì)導(dǎo)致整個(gè)進(jìn)程崩潰一個(gè)線程崩潰會(huì)導(dǎo)致整個(gè)進(jìn)程崩潰用戶級線程用戶級線程線程可以在用戶層或者內(nèi)核層提供線程可以在用戶層或者內(nèi)核層提供在用戶層實(shí)現(xiàn)線程意味著內(nèi)核并不知道線程的存在。在用戶

10、層實(shí)現(xiàn)線程意味著內(nèi)核并不知道線程的存在。用戶層線程庫會(huì)實(shí)現(xiàn)線程的創(chuàng)建、刪除、調(diào)度。用戶層線程庫會(huì)實(shí)現(xiàn)線程的創(chuàng)建、刪除、調(diào)度。用戶層的線程創(chuàng)建比較快用戶層的線程創(chuàng)建比較快當(dāng)某個(gè)線程要使用內(nèi)核時(shí),其余線程都會(huì)被掛起。當(dāng)某個(gè)線程要使用內(nèi)核時(shí),其余線程都會(huì)被掛起。內(nèi)核級線程內(nèi)核級線程內(nèi)核直接支持線程內(nèi)核直接支持線程線程的創(chuàng)建、刪除和調(diào)度都有內(nèi)核來做。線程的創(chuàng)建、刪除和調(diào)度都有內(nèi)核來做。一個(gè)線程等待一個(gè)線程等待I/O阻塞時(shí),其余線程可以繼續(xù)運(yùn)行。阻塞時(shí),其余線程可以繼續(xù)運(yùn)行。創(chuàng)建等操作要進(jìn)出內(nèi)核,速度會(huì)慢些。創(chuàng)建等操作要進(jìn)出內(nèi)核,速度會(huì)慢些。目前流行的操作系統(tǒng)都支持內(nèi)核級線程。目前流行的操作系統(tǒng)都支持內(nèi)

11、核級線程。多線程模型多線程模型內(nèi)核線程和用戶線程的對應(yīng)關(guān)系內(nèi)核線程和用戶線程的對應(yīng)關(guān)系一個(gè)內(nèi)核線程對應(yīng)一個(gè)內(nèi)核線程對應(yīng)n個(gè)用戶線程(用戶級線程)個(gè)用戶線程(用戶級線程)一個(gè)內(nèi)核線程對應(yīng)一個(gè)用戶線程(內(nèi)核級線程)一個(gè)內(nèi)核線程對應(yīng)一個(gè)用戶線程(內(nèi)核級線程)用戶級線程用戶級線程內(nèi)核級線程內(nèi)核級線程多線程中的多線程中的forkfork在在linux系統(tǒng)當(dāng)一個(gè)擁有多線程的進(jìn)程調(diào)用系統(tǒng)當(dāng)一個(gè)擁有多線程的進(jìn)程調(diào)用fork時(shí),時(shí),子進(jìn)程只會(huì)有一個(gè)線程!子進(jìn)程只會(huì)有一個(gè)線程!fork()多線程中的信號多線程中的信號在在linux系統(tǒng)中信號是用來通知進(jìn)程特殊事件發(fā)生系統(tǒng)中信號是用來通知進(jìn)程特殊事件發(fā)生了了多線程中

12、有哪個(gè)線程來處理呢?多線程中有哪個(gè)線程來處理呢?信號會(huì)被遞送給恰當(dāng)?shù)木€程,比如信號會(huì)被遞送給恰當(dāng)?shù)木€程,比如SIGILL非法指非法指令。令。信號會(huì)被遞送給進(jìn)程中任意的線程處理。信號會(huì)被遞送給進(jìn)程中任意的線程處理。在多線程環(huán)境我們一般指定一個(gè)線程專門處理信號,在多線程環(huán)境我們一般指定一個(gè)線程專門處理信號,其余線程全部屏蔽信號處理。其余線程全部屏蔽信號處理。線程池線程池在程序設(shè)計(jì)中,并不是來一個(gè)任務(wù)在程序設(shè)計(jì)中,并不是來一個(gè)任務(wù)/請求就創(chuàng)建一請求就創(chuàng)建一個(gè)線程,執(zhí)行完畢線程退出。個(gè)線程,執(zhí)行完畢線程退出。程序初始化時(shí)創(chuàng)建一個(gè)線程池,線程池中有程序初始化時(shí)創(chuàng)建一個(gè)線程池,線程池中有n個(gè)線個(gè)線程。程。

13、當(dāng)一個(gè)請求來時(shí),從線程池中取一個(gè)線程,完成請當(dāng)一個(gè)請求來時(shí),從線程池中取一個(gè)線程,完成請求后線程再放回線程池。求后線程再放回線程池。節(jié)省了頻繁創(chuàng)建線程和銷毀線程的開銷。節(jié)省了頻繁創(chuàng)建線程和銷毀線程的開銷。pthreadpthread A POSIX standard (IEEE 1003.1c) API for thread creation and synchronization。 pthread大概有大概有60多個(gè)函數(shù),包括線程的創(chuàng)建、終止等。多個(gè)函數(shù),包括線程的創(chuàng)建、終止等。 Linux中實(shí)現(xiàn)了中實(shí)現(xiàn)了pthread線程庫線程庫 Unix/Widows中也有中也有pthread的實(shí)現(xiàn)。的

14、實(shí)現(xiàn)。 Linux中使用中使用pthead方法為:方法為: #include gcc main.c lpthread注意:注意:必須加必須加lpthread,不像,不像glibc庫,庫,gcc不會(huì)自動(dòng)去鏈不會(huì)自動(dòng)去鏈接接pthread庫。庫。線程創(chuàng)建:線程創(chuàng)建:pthread_create()pthread_create()pthread_create用來創(chuàng)建一個(gè)線程。用來創(chuàng)建一個(gè)線程。成功返回成功返回0,失敗返回非,失敗返回非0。thread指向內(nèi)存單元將被設(shè)置為新創(chuàng)建的線程指向內(nèi)存單元將被設(shè)置為新創(chuàng)建的線程ID,attr是要?jiǎng)?chuàng)建線程的屬性(是要?jiǎng)?chuàng)建線程的屬性(NULL為默認(rèn)屬性),為默認(rèn)屬

15、性),start_routine為線程開始執(zhí)行的函數(shù),為線程開始執(zhí)行的函數(shù),arg為為start_routine的參數(shù)。的參數(shù)。線程共享全局變量,在一個(gè)線程中改變對另外線程線程共享全局變量,在一個(gè)線程中改變對另外線程可見??梢姟?include int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);pthread_create()pthread_create()arg不能是局部變量

16、,否則線程使用該變量時(shí)可能不能是局部變量,否則線程使用該變量時(shí)可能已經(jīng)被修改或者不存在了。已經(jīng)被修改或者不存在了。start_routine的參數(shù)和返回值都為的參數(shù)和返回值都為void *,如果如果有多個(gè)參數(shù),那只能打包成一個(gè)結(jié)構(gòu)體了。返回值有多個(gè)參數(shù),那只能打包成一個(gè)結(jié)構(gòu)體了。返回值不能是局部變量!不能是局部變量!主線程退出,則整個(gè)進(jìn)程結(jié)束。主線程退出,則整個(gè)進(jìn)程結(jié)束。線程終止線程終止如果進(jìn)程中的任意線程調(diào)用如果進(jìn)程中的任意線程調(diào)用exit、_exit、_Exit,那么整個(gè)進(jìn)程都會(huì)被終止。那么整個(gè)進(jìn)程都會(huì)被終止。線程從啟動(dòng)函數(shù)中返回,返回值是線程的退出碼。線程從啟動(dòng)函數(shù)中返回,返回值是線程的

17、退出碼。線程可以被其他線程取消線程可以被其他線程取消線程調(diào)用線程調(diào)用pthread_exit退出。退出。pthread_exitpthread_exit調(diào)用調(diào)用pthread_exit后,線程終止。后,線程終止。參數(shù)參數(shù)value_ptr會(huì)被后來調(diào)用會(huì)被后來調(diào)用pthread_join函函數(shù)的線程獲得!數(shù)的線程獲得!pthread_join的第一個(gè)參數(shù)指定某個(gè)線程,第的第一個(gè)參數(shù)指定某個(gè)線程,第二個(gè)參數(shù)用來接收線程的退出值。二個(gè)參數(shù)用來接收線程的退出值。 #include void pthread_exit(void *value_ptr); int pthread_join(pthread_

18、t thread, void *value_ptr);線程線程IDIDpthread_self返回調(diào)用線程的線程返回調(diào)用線程的線程ID。當(dāng)比較兩個(gè)線程是否是同一個(gè)線程,需要用當(dāng)比較兩個(gè)線程是否是同一個(gè)線程,需要用pthread_equal.#include pthread_t pthread_self(void);int pthread_equal(pthread_t t1, pthread_t t2);線程屬性線程屬性 pthread_create的第二個(gè)參數(shù)就是線程的屬性,傳的第二個(gè)參數(shù)就是線程的屬性,傳入入NULL表示使用默認(rèn)屬性。表示使用默認(rèn)屬性。 可以用過可以用過pthread AP

19、I來修改線程的屬性。來修改線程的屬性。線程分離屬性線程分離屬性當(dāng)一個(gè)線程被創(chuàng)建時(shí),系統(tǒng)給它創(chuàng)建一個(gè)線程控制當(dāng)一個(gè)線程被創(chuàng)建時(shí),系統(tǒng)給它創(chuàng)建一個(gè)線程控制塊(塊(由由thread id來標(biāo)識)。如果線程沒有設(shè)置分來標(biāo)識)。如果線程沒有設(shè)置分離屬性,那么需要其它線程通過離屬性,那么需要其它線程通過pthread_join來回收這個(gè)線程控制塊。如果設(shè)置了分離屬性,那來回收這個(gè)線程控制塊。如果設(shè)置了分離屬性,那么線程結(jié)束時(shí)自動(dòng)釋放創(chuàng)建時(shí)分配的資源。么線程結(jié)束時(shí)自動(dòng)釋放創(chuàng)建時(shí)分配的資源。pthread_detach用來設(shè)置分離屬性,但須注意用來設(shè)置分離屬性,但須注意必須在新創(chuàng)建的線程結(jié)束之前!一般來說這個(gè)

20、函數(shù)必須在新創(chuàng)建的線程結(jié)束之前!一般來說這個(gè)函數(shù)是有新建線程進(jìn)入啟動(dòng)函數(shù)后立馬調(diào)用的,是有新建線程進(jìn)入啟動(dòng)函數(shù)后立馬調(diào)用的,pthread_detach(pthread_self()#include int pthread_detach(pthread_t thread);線程屬性線程屬性pthread_attr_init用默認(rèn)值初始化線程的屬性。用默認(rèn)值初始化線程的屬性。成功返回成功返回0,失敗返回非,失敗返回非0值。值。pthread_attr_destroy用來銷毀用來銷毀init分配的內(nèi)分配的內(nèi)存。該函數(shù)理論上都會(huì)執(zhí)行成功,除非你傳入了一存。該函數(shù)理論上都會(huì)執(zhí)行成功,除非你傳入了一個(gè)非

21、法的屬性指針。個(gè)非法的屬性指針。成功返回成功返回0,失敗返回非,失敗返回非0。#include int pthread_attr_destroy(pthread_attr_t *attr);int pthread_attr_init(pthread_attr_t *attr);線程分離屬性線程分離屬性 兩個(gè)函數(shù)的第一個(gè)參數(shù)都是屬性。兩個(gè)函數(shù)的第一個(gè)參數(shù)都是屬性。pthread_attr_setdetachstate用來設(shè)置分離屬性,第二個(gè)參數(shù)有用來設(shè)置分離屬性,第二個(gè)參數(shù)有兩個(gè)值兩個(gè)值PTHREAD_CREATE_DETACHED 和和 PTHREAD_CREATE_JOINABLE。pthr

22、ead_attr_getdetachstate用來獲取分離狀態(tài)。用來獲取分離狀態(tài)。 注意:線程一旦設(shè)置了分離狀態(tài),再調(diào)用注意:線程一旦設(shè)置了分離狀態(tài),再調(diào)用pthread_join就會(huì)出錯(cuò)。就會(huì)出錯(cuò)。#include int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);線程棧屬性線程棧屬性 進(jìn)程??臻g需要被不同的線程共享,所以可能會(huì)出現(xiàn)棧空進(jìn)程??臻g需

23、要被不同的線程共享,所以可能會(huì)出現(xiàn)??臻g不夠的情況。此時(shí)可以用間不夠的情況。此時(shí)可以用malloc從堆中分配內(nèi)存給線程從堆中分配內(nèi)存給線程當(dāng)做棧來使用。當(dāng)做棧來使用。 pthread_attr_setstack設(shè)置堆棧時(shí),第二個(gè)參數(shù)是內(nèi)設(shè)置堆棧時(shí),第二個(gè)參數(shù)是內(nèi)存的起始地址,第三個(gè)參數(shù)為內(nèi)存的大小。存的起始地址,第三個(gè)參數(shù)為內(nèi)存的大小。 pthread_attr_setstacksize可以在不處理?xiàng)7峙涞那榭梢栽诓惶幚項(xiàng)7峙涞那闆r下,改變線程堆棧的大小。況下,改變線程堆棧的大小。#include int pthread_attr_getstack(const pthread_attr_t *

24、restrict attr, void *restrict stackaddr, size_t *restrict stacksize);int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);線程棧屬性線程棧屬性guardsize用來設(shè)置棧溢出后,還可以使用的棧用來設(shè)置棧溢出后,還可以使用的棧的大小,一般為一個(gè)的大小,一般為一個(gè)PAGESIZE

25、。也稱警戒緩沖。也稱警戒緩沖區(qū)。區(qū)。如果我們對如果我們對stackaddr做了修改做了修改 ,那么系統(tǒng)會(huì)假,那么系統(tǒng)會(huì)假設(shè)我們自己會(huì)管理?xiàng)?,不?huì)提供警戒緩沖區(qū)給我們設(shè)我們自己會(huì)管理?xiàng)?,不?huì)提供警戒緩沖區(qū)給我們使用。相當(dāng)于設(shè)置使用。相當(dāng)于設(shè)置guardsize為為0。 #include int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,size_t *restrict guardsize);int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guar

26、dsize);線程同步線程同步當(dāng)多個(gè)線程共享相同的內(nèi)存時(shí),就需要確保每個(gè)線當(dāng)多個(gè)線程共享相同的內(nèi)存時(shí),就需要確保每個(gè)線程看到一致的數(shù)據(jù)。程看到一致的數(shù)據(jù)。如果數(shù)據(jù)是只讀的,那么不存在一致性問題。如果數(shù)據(jù)是只讀的,那么不存在一致性問題。如果線程對數(shù)據(jù)有讀有寫,這時(shí)候就需要同步機(jī)制如果線程對數(shù)據(jù)有讀有寫,這時(shí)候就需要同步機(jī)制來保證數(shù)據(jù)的一致性。來保證數(shù)據(jù)的一致性。線程同步線程同步需要一種機(jī)制確保需要一種機(jī)制確保變量修改時(shí),只有變量修改時(shí),只有一個(gè)線程在訪問。一個(gè)線程在訪問。這樣就能保證數(shù)據(jù)這樣就能保證數(shù)據(jù)的一致性。的一致性?;コ饬炕コ饬课覀兛梢允褂梦覀兛梢允褂胮thread庫提供的互斥量來確保同庫

27、提供的互斥量來確保同一時(shí)間只有一個(gè)線程訪問數(shù)據(jù)。一時(shí)間只有一個(gè)線程訪問數(shù)據(jù)?;コ饬科鋵?shí)就是一種鎖,在訪問共享數(shù)據(jù)之前設(shè)置互斥量其實(shí)就是一種鎖,在訪問共享數(shù)據(jù)之前設(shè)置這個(gè)鎖,訪問完之后釋放這個(gè)鎖。這個(gè)鎖,訪問完之后釋放這個(gè)鎖?;コ饬恳坏┍患恿随i,其他任何線程再也不能在這互斥量一旦被加了鎖,其他任何線程再也不能在這個(gè)互斥量上加鎖,需等到鎖被釋放。個(gè)互斥量上加鎖,需等到鎖被釋放?;コ饬炕コ饬?互斥量的類型為互斥量的類型為pthread_mutex_t,要?jiǎng)?chuàng)建一個(gè)互斥量,要?jiǎng)?chuàng)建一個(gè)互斥量要么使用靜態(tài)方式創(chuàng)建要么使用靜態(tài)方式創(chuàng)建(用用PTHREAD_MUTEX_INITIALIZER 來初始化來初始化)

28、,要么調(diào)用函數(shù)創(chuàng)建。,要么調(diào)用函數(shù)創(chuàng)建。 pthread_mutex_init函數(shù)的第一個(gè)參數(shù)接受該函數(shù)創(chuàng)函數(shù)的第一個(gè)參數(shù)接受該函數(shù)創(chuàng)建的互斥量。第二個(gè)參數(shù)為互斥量屬性,可以為建的互斥量。第二個(gè)參數(shù)為互斥量屬性,可以為NULL。#include int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t * attr);int pthread_mutex_destroy(pthread_mutex_t *mutex);互斥量互斥量pthread_mutex_destroy用來銷毀用來銷毀由由init函函數(shù)創(chuàng)建的

29、互斥量,如果是靜態(tài)創(chuàng)建的則無需調(diào)用數(shù)創(chuàng)建的互斥量,如果是靜態(tài)創(chuàng)建的則無需調(diào)用destroy函數(shù)。函數(shù)。兩個(gè)函數(shù)都是成功返回兩個(gè)函數(shù)都是成功返回0,失敗返回非,失敗返回非0值。值?;コ饬考渔i互斥量加鎖int pthread_mutex_lock(pthread_mutex_t *mutex); 給互斥量給互斥量mutex加鎖。如果此互斥量已經(jīng)加鎖,加鎖。如果此互斥量已經(jīng)加鎖,那么調(diào)用該函數(shù)的線程會(huì)被阻塞,如果互斥量沒加那么調(diào)用該函數(shù)的線程會(huì)被阻塞,如果互斥量沒加鎖,調(diào)用線程給該互斥量加鎖。鎖,調(diào)用線程給該互斥量加鎖。參數(shù)參數(shù)mutex是是由由init函數(shù)創(chuàng)建或者靜態(tài)初始化。函數(shù)創(chuàng)建或者靜態(tài)初始化

30、。成功返回成功返回0,失敗返回非,失敗返回非0.互斥量加鎖互斥量加鎖int pthread_mutex_trylock(pthread_mutex_t *mutex); 只是嘗試加鎖,看鎖是否能加上。只是嘗試加鎖,看鎖是否能加上。如果如果鎖鎖能加上則返回能加上則返回0,不能加上,不能加上errno設(shè)置成設(shè)置成EBUSY,錯(cuò)誤返回其余值。,錯(cuò)誤返回其余值。參數(shù)參數(shù)mutex跟跟lock函數(shù)一樣。函數(shù)一樣。線程可以用線程可以用trylock去檢查某個(gè)去檢查某個(gè)mutex是否加鎖。是否加鎖。如果加鎖了,它就先去執(zhí)行其它任務(wù),以此增加并如果加鎖了,它就先去執(zhí)行其它任務(wù),以此增加并發(fā)性!發(fā)性!互斥量解鎖

31、互斥量解鎖int pthread_mutex_unlock(pthread_mutex_t*mutex);釋放互斥量釋放互斥量成功返回成功返回0,失敗返回非,失敗返回非0死鎖問題死鎖問題如果線程已經(jīng)對互斥量加鎖了,再對這個(gè)互斥量調(diào)如果線程已經(jīng)對互斥量加鎖了,再對這個(gè)互斥量調(diào)用用pthread_mutex_lock,那么此時(shí)該線程被,那么此時(shí)該線程被死鎖。死鎖。假設(shè)有假設(shè)有A、B兩個(gè)互斥量,線程兩個(gè)互斥量,線程A先對先對A互斥量加鎖,互斥量加鎖,然后線程然后線程B對對B互斥量加鎖,然后線程互斥量加鎖,然后線程A又去對又去對B互互斥量加鎖,而線程斥量加鎖,而線程B又去對又去對A互斥量加鎖。此時(shí)兩互

32、斥量加鎖。此時(shí)兩個(gè)線程產(chǎn)生死鎖。個(gè)線程產(chǎn)生死鎖。有多個(gè)互斥量時(shí),要注意加鎖的次序以避免死鎖。有多個(gè)互斥量時(shí),要注意加鎖的次序以避免死鎖。讀寫鎖讀寫鎖 讀寫鎖提供了比互斥量更好的并發(fā)性。讀寫鎖提供了比互斥量更好的并發(fā)性。 互斥量只有加鎖和不加鎖兩個(gè)狀態(tài),同一時(shí)間只允許一個(gè)互斥量只有加鎖和不加鎖兩個(gè)狀態(tài),同一時(shí)間只允許一個(gè)線程加鎖。線程加鎖。 讀寫鎖有三個(gè)狀態(tài):讀鎖、寫鎖、不加鎖。同一時(shí)刻只有讀寫鎖有三個(gè)狀態(tài):讀鎖、寫鎖、不加鎖。同一時(shí)刻只有一個(gè)線程能擁有寫鎖,但是同一時(shí)刻可以有多個(gè)線程可以一個(gè)線程能擁有寫鎖,但是同一時(shí)刻可以有多個(gè)線程可以擁有讀鎖。擁有讀鎖。 加了寫鎖后,任何線程都不能再加鎖。加

33、了寫鎖后,任何線程都不能再加鎖。 加了讀鎖后,任何線程都可以對它加讀鎖,只有一個(gè)能加加了讀鎖后,任何線程都可以對它加讀鎖,只有一個(gè)能加寫鎖。寫鎖。 讀寫鎖適合讀比較頻繁,寫比較少的情況,比如數(shù)據(jù)庫。讀寫鎖適合讀比較頻繁,寫比較少的情況,比如數(shù)據(jù)庫。讀寫鎖讀寫鎖int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); 第一個(gè)參數(shù)返回讀寫鎖對象,

34、第二個(gè)參數(shù)使用第一個(gè)參數(shù)返回讀寫鎖對象,第二個(gè)參數(shù)使用NULL表示默認(rèn)屬性。表示默認(rèn)屬性。返回返回0表示成功,失敗返回非表示成功,失敗返回非0。當(dāng)要釋放讀寫鎖時(shí),必須先調(diào)用當(dāng)要釋放讀寫鎖時(shí),必須先調(diào)用destroy函數(shù)!函數(shù)!PTHREAD_RWLOCK_INITIALIZER 可以初可以初始化靜態(tài)分配的讀寫鎖。始化靜態(tài)分配的讀寫鎖。讀寫鎖讀寫鎖int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_u

35、nlock(pthread_rwlock_t *rwlock); 加讀鎖時(shí)要注意判斷返回值,因?yàn)榧幼x鎖的次數(shù)可能有限加讀鎖時(shí)要注意判斷返回值,因?yàn)榧幼x鎖的次數(shù)可能有限制!所以加讀鎖是會(huì)失敗的。制!所以加讀鎖是會(huì)失敗的。 加寫鎖無須判斷返回值,寫鎖只能加一次。加寫鎖無須判斷返回值,寫鎖只能加一次。 無論加的是寫鎖還是讀鎖,都用無論加的是寫鎖還是讀鎖,都用pthread_rwlock_unlock解解鎖。鎖。 成功返回成功返回0,不成功返回非,不成功返回非0讀寫鎖讀寫鎖int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthre

36、ad_rwlock_trywrlock(pthread_rwlock_t *rwlock); 檢查是否能加鎖,能加鎖返回檢查是否能加鎖,能加鎖返回0,不能加鎖返回,不能加鎖返回EBUSY,失敗返回其余值。,失敗返回其余值。tryrdlock和和trywrlock可以提高并發(fā)性??梢蕴岣卟l(fā)性。條件變量條件變量條件變量是另一種同步機(jī)制。條件變量是另一種同步機(jī)制。多個(gè)線程可以等待同一個(gè)條件,條件滿足時(shí)被喚醒。多個(gè)線程可以等待同一個(gè)條件,條件滿足時(shí)被喚醒??梢詥拘岩粋€(gè)線程,也可以喚醒所有等待的線程??梢詥拘岩粋€(gè)線程,也可以喚醒所有等待的線程。條件變量跟互斥量條件變量跟互斥量mutex一起使用。一起使

37、用。條件變量的類型是條件變量的類型是pthread_cond_t條件變量條件變量int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); 條件變量可以用條件變量可以用PTHREAD_COND_INITIALIZER 靜靜態(tài)初始化。態(tài)初始化。 函數(shù)函數(shù)pthread_cond_init動(dòng)態(tài)的初始化條件變量,第二動(dòng)態(tài)的初始化條件變量,第二個(gè)參數(shù)為個(gè)參數(shù)為NULL,使用默認(rèn)屬性。,使用默

38、認(rèn)屬性。 條件變量需要條件變量需要destroy函數(shù)釋放。函數(shù)釋放。 成功返回成功返回0,失敗返回其余值。,失敗返回其余值。條件變量條件變量int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout); pthread_co

39、nd_wait第一個(gè)參數(shù)為初始化后的條件變量,第一個(gè)參數(shù)為初始化后的條件變量,第二個(gè)參數(shù)為初始化后的互斥量。首先會(huì)被調(diào)用線第二個(gè)參數(shù)為初始化后的互斥量。首先會(huì)被調(diào)用線程放入等待條件變量的隊(duì)列,然后釋放程放入等待條件變量的隊(duì)列,然后釋放mutex,直到條件滿足時(shí)被喚醒,喚醒從函數(shù)返回時(shí)直到條件滿足時(shí)被喚醒,喚醒從函數(shù)返回時(shí)再再對對mutx加鎖。加鎖。 pthread_cond_timewait比第一個(gè)函數(shù)多一個(gè)參數(shù),這比第一個(gè)函數(shù)多一個(gè)參數(shù),這個(gè)參數(shù)指定了等待時(shí)間。如果時(shí)間到了還沒個(gè)參數(shù)指定了等待時(shí)間。如果時(shí)間到了還沒被被喚醒,喚醒,那么返回那么返回ETIMEDOUT條件變量條件變量int pt

40、hread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); 喚醒等待在條件變量上的線程,如果沒有線程等待喚醒等待在條件變量上的線程,如果沒有線程等待在條件變量上,這個(gè)喚醒動(dòng)作是不會(huì)被保留的!在條件變量上,這個(gè)喚醒動(dòng)作是不會(huì)被保留的!函數(shù)函數(shù)pthread_cond_signal只會(huì)喚醒其中一個(gè)只會(huì)喚醒其中一個(gè)線程,線程,pthread_cond_broadcast喚醒所有線程。喚醒所有線程。條件變量使用條件變量使用 多個(gè)線程等待一個(gè)計(jì)數(shù)器達(dá)到一個(gè)值時(shí)被喚醒。多個(gè)線程等待一個(gè)

41、計(jì)數(shù)器達(dá)到一個(gè)值時(shí)被喚醒。 Thread A pthread_mutex_lock(&lock);count +;if (count =MAX_COUNT) pthread_cond_signal( &cond);pthread_mutex_unlock(&lock) Thread Bpthread_mutex_lock(&lock);while (count =MAX_COUNT) pthread_cond_signal( &cond);pthread_mutex_unlock(&lock)Thread Bpthread_mutex_lock(&lock);while (count MAX_

42、COUNT) pthread_mutex_unlock(&lock) pthread_cond_wait(&cond);pthread_mutex_lock(&lock); count-;pthread_mutex_unlock(&lock)條件變量使用條件變量使用 Thread A 當(dāng)滿足條件時(shí)候發(fā)一個(gè)信號。當(dāng)滿足條件時(shí)候發(fā)一個(gè)信號。 ThreadB 先給一個(gè)先給一個(gè)mutex加鎖,以便互斥訪問加鎖,以便互斥訪問count的值。的值。 在一個(gè)在一個(gè)while循環(huán)里等待循環(huán)里等待count值達(dá)到值達(dá)到MAX_COUNT。因?yàn)楫?dāng)某個(gè)條件滿足時(shí),可能會(huì)有多個(gè)線程被喚醒你,所因?yàn)楫?dāng)某個(gè)條件滿足時(shí),可

43、能會(huì)有多個(gè)線程被喚醒你,所以需要判斷條件是否還滿足。以需要判斷條件是否還滿足。 pthread_cond_wait首先把調(diào)用線程放入條件變量的等首先把調(diào)用線程放入條件變量的等待隊(duì)列,然后再釋放待隊(duì)列,然后再釋放mutex。當(dāng)函數(shù)返回時(shí),。當(dāng)函數(shù)返回時(shí),mutex又又會(huì)被加上鎖。會(huì)被加上鎖。 最后會(huì)對最后會(huì)對mutex解鎖,讓其他線程使用解鎖,讓其他線程使用count變量。變量?;コ饬繉傩曰コ饬繉傩?pthread_mutexattr_init用默認(rèn)的屬性互斥量屬性初用默認(rèn)的屬性互斥量屬性初始化始化attr init函數(shù)初始化的互斥量屬性必須由函數(shù)初始化的互斥量屬性必須由pthread_mute

44、xattr_destroy來釋放。來釋放。 互斥量有互斥量有進(jìn)程共享進(jìn)程共享屬性和屬性和類型類型屬性。屬性。#include int pthread_mutexattr_init(pthread_mutexattr_t *attr);int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);互斥量屬性互斥量屬性互斥量進(jìn)程共享屬性互斥量進(jìn)程共享屬性當(dāng)互斥量只在同一進(jìn)程的不同線程使用時(shí),當(dāng)互斥量只在同一進(jìn)程的不同線程使用時(shí),pshared應(yīng)該設(shè)置為應(yīng)該設(shè)置為PTHREAD_PROCESS_PRIVATE 當(dāng)互斥量在不同進(jìn)程間以共享內(nèi)存方式使用

45、時(shí),當(dāng)互斥量在不同進(jìn)程間以共享內(nèi)存方式使用時(shí),pshared應(yīng)該設(shè)置為應(yīng)該設(shè)置為PTHREAD_PROCESS_SHARED #include int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);互斥量類型屬性互斥量類型屬性#include int pthread_mutexattr_gettype(const

46、 pthread_mutexattr_t *restrict attr, int *restrict type);int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);讀寫鎖屬性讀寫鎖屬性讀寫鎖和條件變量只提供了進(jìn)程共享屬性讀寫鎖和條件變量只提供了進(jìn)程共享屬性#include int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);int pt

47、hread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr, int *restrict pshared);int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,int pshared);#include int pthread_condattr_init(pthread_condattr_t *attr);int pthread_condattr_destroy(pthread_condattr_t *attr);int pthread_cond

48、attr_getpshared(const pthread_condattr_t *restrict attr, int *restrict pshared);int pthread_condattr_setpshared(pthread_condattr_t *attr,int pshared);運(yùn)行一次線程運(yùn)行一次線程有時(shí)候在多線程環(huán)境中只想讓某個(gè)函數(shù)執(zhí)行一次。有時(shí)候在多線程環(huán)境中只想讓某個(gè)函數(shù)執(zhí)行一次。pthread_once保證了保證了initfn只會(huì)運(yùn)行一次。只會(huì)運(yùn)行一次。initflag必須是全局或者靜態(tài)的,不能是局部變量。必須是全局或者靜態(tài)的,不能是局部變量。而且必須初始化為而且

49、必須初始化為PTHREAD_ONCE_INIT #include pthread_once_t initflag = PTHREAD_ONCE_INIT;int pthread_once(pthread_once_t *initflag, void (*initfn)(void);信號量信號量 #includeint sem_init (sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t * sem) sem_init初始化一個(gè)無名信初始化一個(gè)無名信號號量,量,pshared為為1時(shí),該時(shí),該信號量可以在進(jìn)程間使用,為信號量可以在進(jìn)程間使用,為0時(shí)只在當(dāng)前進(jìn)程中使用。時(shí)只在當(dāng)前進(jìn)程中使用。value信號燈的初值。信號燈的初值。 sem_destroy釋放有釋放有sem_init初始化后的信號量。釋初始化后的信號量。釋放時(shí)候必須確保沒有任何線程或者進(jìn)程在使用

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論