




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
1、Linux多線程李杰聰世界不是串行的世界不是串行的真實世界中很多事情都是同時發(fā)生的,而不是按次真實世界中很多事情都是同時發(fā)生的,而不是按次序發(fā)生。序發(fā)生。隨著軟硬件的發(fā)展計算機也進入了并行時代。隨著軟硬件的發(fā)展計算機也進入了并行時代。程序員也應該做好并行程序設計的準備。程序員也應該做好并行程序設計的準備。處理器發(fā)展歷史回顧處理器發(fā)展歷史回顧90年代年代增大指令的并行發(fā)射能力,超標量處增大指令的并行發(fā)射能力,超標量處理器。理器。90年代末期至年代末期至21世紀初世紀初提高主頻提高主頻21世紀世紀超線程,多核技術出現(xiàn),主頻不再決超線程,多核技術出現(xiàn),主頻不再決定定CPU性能。性能。處理器種類處理器
2、種類通用處理器:通用處理器:intel, amd生產(chǎn)。生產(chǎn)。網(wǎng)絡處理器:摩托羅拉,網(wǎng)絡處理器:摩托羅拉, 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 錯誤執(zhí)行(賬戶透支)錯誤執(zhí)行(賬戶透支)Pos1
3、Pos2 Pos2 Pos2 Pos1 Pos1 時間并發(fā)的幾個概念并發(fā)的幾個概念競爭(競爭(race condition):程序執(zhí)行的結(jié)果或者輸程序執(zhí)行的結(jié)果或者輸出取決于某一段代碼的執(zhí)行次序,次序不同結(jié)果不出取決于某一段代碼的執(zhí)行次序,次序不同結(jié)果不同。同。競爭是不確定的,偶發(fā)性較強。競爭是不確定的,偶發(fā)性較強。導致系統(tǒng)異常,數(shù)據(jù)被破壞。導致系統(tǒng)異常,數(shù)據(jù)被破壞。難以重現(xiàn),調(diào)試,發(fā)現(xiàn)競爭。難以重現(xiàn),調(diào)試,發(fā)現(xiàn)競爭。加入調(diào)試代碼時,競爭會消失?!加入調(diào)試代碼時,競爭會消失?!銀行卡存在數(shù)據(jù)競爭。銀行卡存在數(shù)據(jù)競爭。并發(fā)的幾個概念并發(fā)的幾個概念原子性(原子性(atomic):是系統(tǒng)中最小的一個
4、操作集合。是系統(tǒng)中最小的一個操作集合。銀行卡例子中,更新賬戶余額的操作集合需要時一銀行卡例子中,更新賬戶余額的操作集合需要時一個原子操作。也即個原子操作。也即 是一個原子操作,否則引是一個原子操作,否則引入競爭。導致程序運行結(jié)果不確定。入競爭。導致程序運行結(jié)果不確定。也可把也可把 作為原子操作,但會降低程序性作為原子操作,但會降低程序性能。能。對競爭的判斷同時也是對原子操作范圍的界定。對競爭的判斷同時也是對原子操作范圍的界定。程序設計中,競爭區(qū)域判斷比想象中要困難很多。程序設計中,競爭區(qū)域判斷比想象中要困難很多。哲學家問題哲學家問題有有5個哲學家圍坐在一張圓桌上。個哲學家圍坐在一張圓桌上。每相
5、鄰兩個哲學家之間有一只筷每相鄰兩個哲學家之間有一只筷子。子。哲學家除了思考就是吃。哲學家除了思考就是吃。當哲學家餓時,他就先拿起作手當哲學家餓時,他就先拿起作手邊的筷子然后再拿右手邊的筷子邊的筷子然后再拿右手邊的筷子 。當有兩只筷子時,哲學家開始吃當有兩只筷子時,哲學家開始吃飯,否則一直等待另外一只筷子。飯,否則一直等待另外一只筷子。哲學家吃晚飯后,放下筷子,繼哲學家吃晚飯后,放下筷子,繼續(xù)思考。續(xù)思考。并發(fā)中的問題并發(fā)中的問題死鎖死鎖 (deadlock):兩個或者以上的線程互相):兩個或者以上的線程互相等待,導致整個系統(tǒng)無法向前推進。等待,導致整個系統(tǒng)無法向前推進。例如:例如:5個哲學家同
6、時拿起自己左手邊的筷子,然個哲學家同時拿起自己左手邊的筷子,然后等待右手邊的筷子。由于所有筷子均被占有,導后等待右手邊的筷子。由于所有筷子均被占有,導致沒有一個哲學家能進食。致沒有一個哲學家能進食。并發(fā)中的問題并發(fā)中的問題活鎖(活鎖(livelock):兩個或者以上的線程會不斷):兩個或者以上的線程會不斷的執(zhí)行,不斷的改變狀態(tài),但整個系統(tǒng)卻不朝著最的執(zhí)行,不斷的改變狀態(tài),但整個系統(tǒng)卻不朝著最終目的前進。終目的前進?;铈i一般為了解決死鎖引入的。死鎖的線程只會等活鎖一般為了解決死鎖引入的。死鎖的線程只會等待,不會改變狀態(tài)?;铈i會改變執(zhí)行狀態(tài),但不會待,不會改變狀態(tài)?;铈i會改變執(zhí)行狀態(tài),但不會朝著最
7、終目標前進。朝著最終目標前進。為了解決哲學家的死鎖問題。我們規(guī)定:如果哲學為了解決哲學家的死鎖問題。我們規(guī)定:如果哲學家無法拿到右手邊的筷子,那么他必須放下他左手家無法拿到右手邊的筷子,那么他必須放下他左手邊的筷子。等待一會兒再去嘗試拿筷子。邊的筷子。等待一會兒再去嘗試拿筷子。舉例:舉例:5個哲學同時拿起左手邊筷子,個哲學同時拿起左手邊筷子, 發(fā)現(xiàn)右手邊發(fā)現(xiàn)右手邊的筷子沒有,又同時放下左手上的筷子,如此往復的筷子沒有,又同時放下左手上的筷子,如此往復并發(fā)中的問題并發(fā)中的問題饑餓、餓死(饑餓、餓死(starvation):某些線程永遠無法得某些線程永遠無法得到執(zhí)行的機會。到執(zhí)行的機會。舉例:某一
8、哲學家,每次去拿筷子時,左手或者右舉例:某一哲學家,每次去拿筷子時,左手或者右手邊的筷子被拿走,該哲學家只能一直手邊的筷子被拿走,該哲學家只能一直“餓肚子餓肚子”。公平性(公平性(fairness):有些線程得到的執(zhí)行機會):有些線程得到的執(zhí)行機會多,多, 有些線程得到的執(zhí)行機會少。有些線程得到的執(zhí)行機會少。舉例:哲學家在拿筷子時,有些哲學家拿到筷子的舉例:哲學家在拿筷子時,有些哲學家拿到筷子的可能性可能比其它哲學家大。比如那些好吃懶做,可能性可能比其它哲學家大。比如那些好吃懶做,整天嘗試去拿筷子的哲學家。整天嘗試去拿筷子的哲學家。多線程概念多線程概念 進程是資源分配的對象,時間片內(nèi)存等。進程
9、是資源分配的對象,時間片內(nèi)存等。 線程是使用資源的實體,一個進程中的多個線程共享內(nèi)存,全局變量,線程是使用資源的實體,一個進程中的多個線程共享內(nèi)存,全局變量, 文件文件描述符等。描述符等。 線程有獨立的棧和寄存器線程有獨立的棧和寄存器線程的優(yōu)缺點線程的優(yōu)缺點優(yōu)點:優(yōu)點: 上下文切換快上下文切換快 共享數(shù)據(jù)容易共享數(shù)據(jù)容易 創(chuàng)建線程速度快創(chuàng)建線程速度快缺點缺點 內(nèi)存共享會導致互相干擾內(nèi)存共享會導致互相干擾 一個線程崩潰會導致整個進程崩潰一個線程崩潰會導致整個進程崩潰用戶級線程用戶級線程線程可以在用戶層或者內(nèi)核層提供線程可以在用戶層或者內(nèi)核層提供在用戶層實現(xiàn)線程意味著內(nèi)核并不知道線程的存在。在用戶
10、層實現(xiàn)線程意味著內(nèi)核并不知道線程的存在。用戶層線程庫會實現(xiàn)線程的創(chuàng)建、刪除、調(diào)度。用戶層線程庫會實現(xiàn)線程的創(chuàng)建、刪除、調(diào)度。用戶層的線程創(chuàng)建比較快用戶層的線程創(chuàng)建比較快當某個線程要使用內(nèi)核時,其余線程都會被掛起。當某個線程要使用內(nèi)核時,其余線程都會被掛起。內(nèi)核級線程內(nèi)核級線程內(nèi)核直接支持線程內(nèi)核直接支持線程線程的創(chuàng)建、刪除和調(diào)度都有內(nèi)核來做。線程的創(chuàng)建、刪除和調(diào)度都有內(nèi)核來做。一個線程等待一個線程等待I/O阻塞時,其余線程可以繼續(xù)運行。阻塞時,其余線程可以繼續(xù)運行。創(chuàng)建等操作要進出內(nèi)核,速度會慢些。創(chuàng)建等操作要進出內(nèi)核,速度會慢些。目前流行的操作系統(tǒng)都支持內(nèi)核級線程。目前流行的操作系統(tǒng)都支持內(nèi)
11、核級線程。多線程模型多線程模型內(nèi)核線程和用戶線程的對應關系內(nèi)核線程和用戶線程的對應關系一個內(nèi)核線程對應一個內(nèi)核線程對應n個用戶線程(用戶級線程)個用戶線程(用戶級線程)一個內(nèi)核線程對應一個用戶線程(內(nèi)核級線程)一個內(nèi)核線程對應一個用戶線程(內(nèi)核級線程)用戶級線程用戶級線程內(nèi)核級線程內(nèi)核級線程多線程中的多線程中的forkfork在在linux系統(tǒng)當一個擁有多線程的進程調(diào)用系統(tǒng)當一個擁有多線程的進程調(diào)用fork時,時,子進程只會有一個線程!子進程只會有一個線程!fork()多線程中的信號多線程中的信號在在linux系統(tǒng)中信號是用來通知進程特殊事件發(fā)生系統(tǒng)中信號是用來通知進程特殊事件發(fā)生了了多線程中
12、有哪個線程來處理呢?多線程中有哪個線程來處理呢?信號會被遞送給恰當?shù)木€程,比如信號會被遞送給恰當?shù)木€程,比如SIGILL非法指非法指令。令。信號會被遞送給進程中任意的線程處理。信號會被遞送給進程中任意的線程處理。在多線程環(huán)境我們一般指定一個線程專門處理信號,在多線程環(huán)境我們一般指定一個線程專門處理信號,其余線程全部屏蔽信號處理。其余線程全部屏蔽信號處理。線程池線程池在程序設計中,并不是來一個任務在程序設計中,并不是來一個任務/請求就創(chuàng)建一請求就創(chuàng)建一個線程,執(zhí)行完畢線程退出。個線程,執(zhí)行完畢線程退出。程序初始化時創(chuàng)建一個線程池,線程池中有程序初始化時創(chuàng)建一個線程池,線程池中有n個線個線程。程。
13、當一個請求來時,從線程池中取一個線程,完成請當一個請求來時,從線程池中取一個線程,完成請求后線程再放回線程池。求后線程再放回線程池。節(jié)省了頻繁創(chuàng)建線程和銷毀線程的開銷。節(jié)省了頻繁創(chuàng)建線程和銷毀線程的開銷。pthreadpthread A POSIX standard (IEEE 1003.1c) API for thread creation and synchronization。 pthread大概有大概有60多個函數(shù),包括線程的創(chuàng)建、終止等。多個函數(shù),包括線程的創(chuàng)建、終止等。 Linux中實現(xiàn)了中實現(xiàn)了pthread線程庫線程庫 Unix/Widows中也有中也有pthread的實現(xiàn)。的
14、實現(xiàn)。 Linux中使用中使用pthead方法為:方法為: #include gcc main.c lpthread注意:注意:必須加必須加lpthread,不像,不像glibc庫,庫,gcc不會自動去鏈不會自動去鏈接接pthread庫。庫。線程創(chuàng)建:線程創(chuàng)建:pthread_create()pthread_create()pthread_create用來創(chuàng)建一個線程。用來創(chuàng)建一個線程。成功返回成功返回0,失敗返回非,失敗返回非0。thread指向內(nèi)存單元將被設置為新創(chuàng)建的線程指向內(nèi)存單元將被設置為新創(chuàng)建的線程ID,attr是要創(chuàng)建線程的屬性(是要創(chuàng)建線程的屬性(NULL為默認屬性),為默認屬
15、性),start_routine為線程開始執(zhí)行的函數(shù),為線程開始執(zhí)行的函數(shù),arg為為start_routine的參數(shù)。的參數(shù)。線程共享全局變量,在一個線程中改變對另外線程線程共享全局變量,在一個線程中改變對另外線程可見??梢?。#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、,否則線程使用該變量時可能不能是局部變量,否則線程使用該變量時可能已經(jīng)被修改或者不存在了。已經(jīng)被修改或者不存在了。start_routine的參數(shù)和返回值都為的參數(shù)和返回值都為void *,如果如果有多個參數(shù),那只能打包成一個結(jié)構(gòu)體了。返回值有多個參數(shù),那只能打包成一個結(jié)構(gòu)體了。返回值不能是局部變量!不能是局部變量!主線程退出,則整個進程結(jié)束。主線程退出,則整個進程結(jié)束。線程終止線程終止如果進程中的任意線程調(diào)用如果進程中的任意線程調(diào)用exit、_exit、_Exit,那么整個進程都會被終止。那么整個進程都會被終止。線程從啟動函數(shù)中返回,返回值是線程的退出碼。線程從啟動函數(shù)中返回,返回值是線程的
17、退出碼。線程可以被其他線程取消線程可以被其他線程取消線程調(diào)用線程調(diào)用pthread_exit退出。退出。pthread_exitpthread_exit調(diào)用調(diào)用pthread_exit后,線程終止。后,線程終止。參數(shù)參數(shù)value_ptr會被后來調(diào)用會被后來調(diào)用pthread_join函函數(shù)的線程獲得!數(shù)的線程獲得!pthread_join的第一個參數(shù)指定某個線程,第的第一個參數(shù)指定某個線程,第二個參數(shù)用來接收線程的退出值。二個參數(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。當比較兩個線程是否是同一個線程,需要用當比較兩個線程是否是同一個線程,需要用pthread_equal.#include pthread_t pthread_self(void);int pthread_equal(pthread_t t1, pthread_t t2);線程屬性線程屬性 pthread_create的第二個參數(shù)就是線程的屬性,傳的第二個參數(shù)就是線程的屬性,傳入入NULL表示使用默認屬性。表示使用默認屬性。 可以用過可以用過pthread AP
19、I來修改線程的屬性。來修改線程的屬性。線程分離屬性線程分離屬性當一個線程被創(chuàng)建時,系統(tǒng)給它創(chuàng)建一個線程控制當一個線程被創(chuàng)建時,系統(tǒng)給它創(chuàng)建一個線程控制塊(塊(由由thread id來標識)。如果線程沒有設置分來標識)。如果線程沒有設置分離屬性,那么需要其它線程通過離屬性,那么需要其它線程通過pthread_join來回收這個線程控制塊。如果設置了分離屬性,那來回收這個線程控制塊。如果設置了分離屬性,那么線程結(jié)束時自動釋放創(chuàng)建時分配的資源。么線程結(jié)束時自動釋放創(chuàng)建時分配的資源。pthread_detach用來設置分離屬性,但須注意用來設置分離屬性,但須注意必須在新創(chuàng)建的線程結(jié)束之前!一般來說這個
20、函數(shù)必須在新創(chuàng)建的線程結(jié)束之前!一般來說這個函數(shù)是有新建線程進入啟動函數(shù)后立馬調(diào)用的,是有新建線程進入啟動函數(shù)后立馬調(diào)用的,pthread_detach(pthread_self()#include int pthread_detach(pthread_t thread);線程屬性線程屬性pthread_attr_init用默認值初始化線程的屬性。用默認值初始化線程的屬性。成功返回成功返回0,失敗返回非,失敗返回非0值。值。pthread_attr_destroy用來銷毀用來銷毀init分配的內(nèi)分配的內(nèi)存。該函數(shù)理論上都會執(zhí)行成功,除非你傳入了一存。該函數(shù)理論上都會執(zhí)行成功,除非你傳入了一個非
21、法的屬性指針。個非法的屬性指針。成功返回成功返回0,失敗返回非,失敗返回非0。#include int pthread_attr_destroy(pthread_attr_t *attr);int pthread_attr_init(pthread_attr_t *attr);線程分離屬性線程分離屬性 兩個函數(shù)的第一個參數(shù)都是屬性。兩個函數(shù)的第一個參數(shù)都是屬性。pthread_attr_setdetachstate用來設置分離屬性,第二個參數(shù)有用來設置分離屬性,第二個參數(shù)有兩個值兩個值PTHREAD_CREATE_DETACHED 和和 PTHREAD_CREATE_JOINABLE。pthr
22、ead_attr_getdetachstate用來獲取分離狀態(tài)。用來獲取分離狀態(tài)。 注意:線程一旦設置了分離狀態(tài),再調(diào)用注意:線程一旦設置了分離狀態(tài),再調(diào)用pthread_join就會出錯。就會出錯。#include int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);線程棧屬性線程棧屬性 進程??臻g需要被不同的線程共享,所以可能會出現(xiàn)??者M程??臻g需
23、要被不同的線程共享,所以可能會出現(xiàn)??臻g不夠的情況。此時可以用間不夠的情況。此時可以用malloc從堆中分配內(nèi)存給線程從堆中分配內(nèi)存給線程當做棧來使用。當做棧來使用。 pthread_attr_setstack設置堆棧時,第二個參數(shù)是內(nèi)設置堆棧時,第二個參數(shù)是內(nèi)存的起始地址,第三個參數(shù)為內(nèi)存的大小。存的起始地址,第三個參數(shù)為內(nèi)存的大小。 pthread_attr_setstacksize可以在不處理棧分配的情可以在不處理棧分配的情況下,改變線程堆棧的大小。況下,改變線程堆棧的大小。#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用來設置棧溢出后,還可以使用的棧用來設置棧溢出后,還可以使用的棧的大小,一般為一個的大小,一般為一個PAGESIZE
25、。也稱警戒緩沖。也稱警戒緩沖區(qū)。區(qū)。如果我們對如果我們對stackaddr做了修改做了修改 ,那么系統(tǒng)會假,那么系統(tǒng)會假設我們自己會管理棧,不會提供警戒緩沖區(qū)給我們設我們自己會管理棧,不會提供警戒緩沖區(qū)給我們使用。相當于設置使用。相當于設置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);線程同步線程同步當多個線程共享相同的內(nèi)存時,就需要確保每個線當多個線程共享相同的內(nèi)存時,就需要確保每個線程看到一致的數(shù)據(jù)。程看到一致的數(shù)據(jù)。如果數(shù)據(jù)是只讀的,那么不存在一致性問題。如果數(shù)據(jù)是只讀的,那么不存在一致性問題。如果線程對數(shù)據(jù)有讀有寫,這時候就需要同步機制如果線程對數(shù)據(jù)有讀有寫,這時候就需要同步機制來保證數(shù)據(jù)的一致性。來保證數(shù)據(jù)的一致性。線程同步線程同步需要一種機制確保需要一種機制確保變量修改時,只有變量修改時,只有一個線程在訪問。一個線程在訪問。這樣就能保證數(shù)據(jù)這樣就能保證數(shù)據(jù)的一致性。的一致性?;コ饬炕コ饬课覀兛梢允褂梦覀兛梢允褂胮thread庫提供的互斥量來確保同庫
27、提供的互斥量來確保同一時間只有一個線程訪問數(shù)據(jù)。一時間只有一個線程訪問數(shù)據(jù)?;コ饬科鋵嵕褪且环N鎖,在訪問共享數(shù)據(jù)之前設置互斥量其實就是一種鎖,在訪問共享數(shù)據(jù)之前設置這個鎖,訪問完之后釋放這個鎖。這個鎖,訪問完之后釋放這個鎖?;コ饬恳坏┍患恿随i,其他任何線程再也不能在這互斥量一旦被加了鎖,其他任何線程再也不能在這個互斥量上加鎖,需等到鎖被釋放。個互斥量上加鎖,需等到鎖被釋放?;コ饬炕コ饬?互斥量的類型為互斥量的類型為pthread_mutex_t,要創(chuàng)建一個互斥量,要創(chuàng)建一個互斥量要么使用靜態(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ù)的第一個參數(shù)接受該函數(shù)創(chuàng)函數(shù)的第一個參數(shù)接受該函數(shù)創(chuàng)建的互斥量。第二個參數(shù)為互斥量屬性,可以為建的互斥量。第二個參數(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ù)。兩個函數(shù)都是成功返回兩個函數(shù)都是成功返回0,失敗返回非,失敗返回非0值。值?;コ饬考渔i互斥量加鎖int pthread_mutex_lock(pthread_mutex_t *mutex); 給互斥量給互斥量mutex加鎖。如果此互斥量已經(jīng)加鎖,加鎖。如果此互斥量已經(jīng)加鎖,那么調(diào)用該函數(shù)的線程會被阻塞,如果互斥量沒加那么調(diào)用該函數(shù)的線程會被阻塞,如果互斥量沒加鎖,調(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設置成設置成EBUSY,錯誤返回其余值。,錯誤返回其余值。參數(shù)參數(shù)mutex跟跟lock函數(shù)一樣。函數(shù)一樣。線程可以用線程可以用trylock去檢查某個去檢查某個mutex是否加鎖。是否加鎖。如果加鎖了,它就先去執(zhí)行其它任務,以此增加并如果加鎖了,它就先去執(zhí)行其它任務,以此增加并發(fā)性!發(fā)性!互斥量解鎖
31、互斥量解鎖int pthread_mutex_unlock(pthread_mutex_t*mutex);釋放互斥量釋放互斥量成功返回成功返回0,失敗返回非,失敗返回非0死鎖問題死鎖問題如果線程已經(jīng)對互斥量加鎖了,再對這個互斥量調(diào)如果線程已經(jīng)對互斥量加鎖了,再對這個互斥量調(diào)用用pthread_mutex_lock,那么此時該線程被,那么此時該線程被死鎖。死鎖。假設有假設有A、B兩個互斥量,線程兩個互斥量,線程A先對先對A互斥量加鎖,互斥量加鎖,然后線程然后線程B對對B互斥量加鎖,然后線程互斥量加鎖,然后線程A又去對又去對B互互斥量加鎖,而線程斥量加鎖,而線程B又去對又去對A互斥量加鎖。此時兩互
32、斥量加鎖。此時兩個線程產(chǎn)生死鎖。個線程產(chǎn)生死鎖。有多個互斥量時,要注意加鎖的次序以避免死鎖。有多個互斥量時,要注意加鎖的次序以避免死鎖。讀寫鎖讀寫鎖 讀寫鎖提供了比互斥量更好的并發(fā)性。讀寫鎖提供了比互斥量更好的并發(fā)性。 互斥量只有加鎖和不加鎖兩個狀態(tài),同一時間只允許一個互斥量只有加鎖和不加鎖兩個狀態(tài),同一時間只允許一個線程加鎖。線程加鎖。 讀寫鎖有三個狀態(tài):讀鎖、寫鎖、不加鎖。同一時刻只有讀寫鎖有三個狀態(tài):讀鎖、寫鎖、不加鎖。同一時刻只有一個線程能擁有寫鎖,但是同一時刻可以有多個線程可以一個線程能擁有寫鎖,但是同一時刻可以有多個線程可以擁有讀鎖。擁有讀鎖。 加了寫鎖后,任何線程都不能再加鎖。加
33、了寫鎖后,任何線程都不能再加鎖。 加了讀鎖后,任何線程都可以對它加讀鎖,只有一個能加加了讀鎖后,任何線程都可以對它加讀鎖,只有一個能加寫鎖。寫鎖。 讀寫鎖適合讀比較頻繁,寫比較少的情況,比如數(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); 第一個參數(shù)返回讀寫鎖對象,
34、第二個參數(shù)使用第一個參數(shù)返回讀寫鎖對象,第二個參數(shù)使用NULL表示默認屬性。表示默認屬性。返回返回0表示成功,失敗返回非表示成功,失敗返回非0。當要釋放讀寫鎖時,必須先調(diào)用當要釋放讀寫鎖時,必須先調(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ù)可能有限加讀鎖時要注意判斷返回值,因為加讀鎖的次數(shù)可能有限制!所以加讀鎖是會失敗的。制!所以加讀鎖是會失敗的。 加寫鎖無須判斷返回值,寫鎖只能加一次。加寫鎖無須判斷返回值,寫鎖只能加一次。 無論加的是寫鎖還是讀鎖,都用無論加的是寫鎖還是讀鎖,都用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ā)性。條件變量條件變量條件變量是另一種同步機制。條件變量是另一種同步機制。多個線程可以等待同一個條件,條件滿足時被喚醒。多個線程可以等待同一個條件,條件滿足時被喚醒??梢詥拘岩粋€線程,也可以喚醒所有等待的線程??梢詥拘岩粋€線程,也可以喚醒所有等待的線程。條件變量跟互斥量條件變量跟互斥量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動態(tài)的初始化條件變量,第二動態(tài)的初始化條件變量,第二個參數(shù)為個參數(shù)為NULL,使用默認屬性。,使用默
38、認屬性。 條件變量需要條件變量需要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第一個參數(shù)為初始化后的條件變量,第一個參數(shù)為初始化后的條件變量,第二個參數(shù)為初始化后的互斥量。首先會被調(diào)用線第二個參數(shù)為初始化后的互斥量。首先會被調(diào)用線程放入等待條件變量的隊列,然后釋放程放入等待條件變量的隊列,然后釋放mutex,直到條件滿足時被喚醒,喚醒從函數(shù)返回時直到條件滿足時被喚醒,喚醒從函數(shù)返回時再再對對mutx加鎖。加鎖。 pthread_cond_timewait比第一個函數(shù)多一個參數(shù),這比第一個函數(shù)多一個參數(shù),這個參數(shù)指定了等待時間。如果時間到了還沒個參數(shù)指定了等待時間。如果時間到了還沒被被喚醒,喚醒,那么返回那么返回ETIMEDOUT條件變量條件變量int pt
40、hread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); 喚醒等待在條件變量上的線程,如果沒有線程等待喚醒等待在條件變量上的線程,如果沒有線程等待在條件變量上,這個喚醒動作是不會被保留的!在條件變量上,這個喚醒動作是不會被保留的!函數(shù)函數(shù)pthread_cond_signal只會喚醒其中一個只會喚醒其中一個線程,線程,pthread_cond_broadcast喚醒所有線程。喚醒所有線程。條件變量使用條件變量使用 多個線程等待一個計數(shù)器達到一個值時被喚醒。多個線程等待一個
41、計數(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 當滿足條件時候發(fā)一個信號。當滿足條件時候發(fā)一個信號。 ThreadB 先給一個先給一個mutex加鎖,以便互斥訪問加鎖,以便互斥訪問count的值。的值。 在一個在一個while循環(huán)里等待循環(huán)里等待count值達到值達到MAX_COUNT。因為當某個條件滿足時,可能會有多個線程被喚醒你,所因為當某個條件滿足時,可
43、能會有多個線程被喚醒你,所以需要判斷條件是否還滿足。以需要判斷條件是否還滿足。 pthread_cond_wait首先把調(diào)用線程放入條件變量的等首先把調(diào)用線程放入條件變量的等待隊列,然后再釋放待隊列,然后再釋放mutex。當函數(shù)返回時,。當函數(shù)返回時,mutex又又會被加上鎖。會被加上鎖。 最后會對最后會對mutex解鎖,讓其他線程使用解鎖,讓其他線程使用count變量。變量?;コ饬繉傩曰コ饬繉傩?pthread_mutexattr_init用默認的屬性互斥量屬性初用默認的屬性互斥量屬性初始化始化attr init函數(shù)初始化的互斥量屬性必須由函數(shù)初始化的互斥量屬性必須由pthread_mute
44、xattr_destroy來釋放。來釋放。 互斥量有互斥量有進程共享進程共享屬性和屬性和類型類型屬性。屬性。#include int pthread_mutexattr_init(pthread_mutexattr_t *attr);int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);互斥量屬性互斥量屬性互斥量進程共享屬性互斥量進程共享屬性當互斥量只在同一進程的不同線程使用時,當互斥量只在同一進程的不同線程使用時,pshared應該設置為應該設置為PTHREAD_PROCESS_PRIVATE 當互斥量在不同進程間以共享內(nèi)存方式使用
45、時,當互斥量在不同進程間以共享內(nèi)存方式使用時,pshared應該設置為應該設置為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);讀寫鎖屬性讀寫鎖屬性讀寫鎖和條件變量只提供了進程共享屬性讀寫鎖和條件變量只提供了進程共享屬性#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);運行一次線程運行一次線程有時候在多線程環(huán)境中只想讓某個函數(shù)執(zhí)行一次。有時候在多線程環(huán)境中只想讓某個函數(shù)執(zhí)行一次。pthread_once保證了保證了initfn只會運行一次。只會運行一次。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初始化一個無名信初始化一個無名信號號量,量,pshared為為1時,該時,該信號量可以在進程間使用,為信號量可以在進程間使用,為0時只在當前進程中使用。時只在當前進程中使用。value信號燈的初值。信號燈的初值。 sem_destroy釋放有釋放有sem_init初始化后的信號量。釋初始化后的信號量。釋放時候必須確保沒有任何線程或者進程在使用
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 公司文明誠信活動方案
- 2025年藥品安全管理考試試題及答案
- 2025年醫(yī)療衛(wèi)生系統(tǒng)綜合能力考試試卷及答案
- 2025年心理治療師認證考試試卷及答案
- 2025年現(xiàn)代職業(yè)教育理論與實踐考試試卷及答案
- 2025年特殊教育教師資格考試卷及答案
- 2025年數(shù)字內(nèi)容運營人才招聘考試試卷及答案
- 2025年人際傳播與關系管理考試試卷及答案
- 追尋生命意義與心理健康
- 做一個身心健康的中學生
- 2024年秋兒童發(fā)展問題的咨詢與輔導終考期末大作業(yè)案例分析1-5答案
- 公安輔警合同模板
- 大學生創(chuàng)新創(chuàng)業(yè)教育(2023秋學期)學習通超星期末考試答案章節(jié)答案2024年
- 中建2024裝配式建筑+鋁模一體化施工技術手冊
- 農(nóng)作物四級種子生產(chǎn)技術規(guī)程 第1部分:小麥DB41-T 293.1-2014
- TSG ZF001-2006《安全閥安全技術監(jiān)察規(guī)程》
- 自動尋優(yōu)控制系統(tǒng)在生料立磨中的應用實踐
- 土地延期合同范本
- 四川省綿陽市涪城區(qū)2024-2025學年七年級上學期開學考試語文試題(解析版)
- DL∕T 796-2012 風力發(fā)電場安全規(guī)程
- 部編版八年級升九年級歷史暑假預習知識清單(填空+答案)
評論
0/150
提交評論