




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
Linux環(huán)境高級編程
李林
電子科技大學(xué)軟件學(xué)院
第三講線程的封裝
李林
電子科技大學(xué)軟件學(xué)院
?線程的基本概念
?線程的創(chuàng)建與終止II
?線程創(chuàng)建的封裝111
.線程的同步
-線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
第二講線程的封裝
.線程的基本概念1111
?線程的創(chuàng)建與終止111
?線程創(chuàng)建的封裝1,11
.線程的同步IIIII
-線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
—線程的概念_________
■進(jìn)程的所有信息對該進(jìn)程的所有線程都是
共享的,包括可執(zhí)行的程序文本、程序的
I全局內(nèi)存、堆內(nèi)存、文件描述符等
■線程獨有的:線程ID、寄存器值、棧、信
.號屏蔽字、errno值、線程私有數(shù)據(jù)
■典型的UNIX進(jìn)程,可以看成是只有一個線
程的進(jìn)程
5
—線程的概念_________
■同進(jìn)程一樣,每個線程也有一個線程ID
■進(jìn)程ID在整個系統(tǒng)中是唯一的,但線程ID
不同,線程ID只在它所屬的進(jìn)程環(huán)境中有
?效一?????????
■線程ID的類型是pthread_t,在Linux中的定
義:
A在/usr/include/bits/pthreadtypes.h中
>typedefunsignedlongintpthread_t;
6
■pthread_self函數(shù)可以使調(diào)用線程獲取自己
的線程后...........................
■函數(shù)原型IIIIIIII
#include<pthread.h>
pthread_tpthread_self();
■返回調(diào)用線程的線程ID
7
—線程的概念_________
■Linux中使用整型表示線程ID,而其他系統(tǒng)
則不一定
■FreeBSD5.2.1>MacOSX10.3用一個指
向pthread結(jié)構(gòu)的指針來表示pthread_t類型。
■為了移植性,在比較兩個線程ID是否相同
時,可以使用pthread_equal函數(shù)
8
pthreadequal^S
■該函數(shù)用于比較兩個線程ID是否相同
■函數(shù)原型.....................11
#include<pthread.h>
intpthread_equal(pthread_ttid1,pthread_ttid2);
■若相等則返回非0值,否則返回0
9
?線程的基本概念
?線程的創(chuàng)建與終止11
?線程創(chuàng)建的封裝111
.線程的同步
-線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
11
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
12
一線程的創(chuàng)建
■pthread_create函數(shù)用于創(chuàng)建一個線程
■函數(shù)原M..................................................
#include<pthread.h>
intpthread_create(pthread_t*restricttidp,
constpthread_attr_t*restrictattr,
void*(*start_rtn)(void*),
void*restrictarg);
■參數(shù)與返回值
>tidp:當(dāng)pthread_create成功返回時,該函數(shù)將線程ID
存儲在tidp指向的內(nèi)存區(qū)域中
13
rest,jet關(guān)鍵字________
■restrict關(guān)鍵字C99標(biāo)準(zhǔn)引入的,
,.只能用于限定指針..................
B表明指針是訪問一個數(shù)據(jù)對象的唯一且初始
的方式
resjcj;關(guān)鍵字________
intar[10];
int*restrictrestar=(int*)malloc(10*sizeof(int));
int*par=ar;
for(intn=0;n<10;n++){、
par[n]+=5;A
.restar[n]+=5;?'int*pnew=restar;
HB]i[[\_______________________?
ar[n]*=2;
par[n]+=3;
restar[n]+=3;
}
resjcj;關(guān)鍵字________
intar[10];
int*restrictrestar=(jnt*)malloc(10*sizeof(int));
int*par=ar;
for(intn=0;n<10;n++){/
par[n]+=5;~~/-------------\
『estar[n]+=5;::[int*吵(restar;
ar[n]*=2;/
par[n]+=3;
restar[n]+=3;
re&±rjet關(guān)鍵字
intar[10];
int*restrictrestar=(int*)malloc(1O*sizeof(int));
int*par=ar;
for(intn=0;n<10;n++){
par[n]+=5;
對restar的操作進(jìn)行優(yōu)化,
restar[n]+=8
restar[n]+=5;
無法對par的操作優(yōu)化
Lr[n]*=2;]
par[n]+=8
I什么是編譯單元?
par[n]+=3;
restar[n]+=3;
}
pthreadcrgate函數(shù)
■參數(shù)與返回值11111
0>attr:用于定制各種不同的線程屬性,將在后
面部分討論。通??稍O(shè)為NULL,采用默認(rèn)線
J呈扈性
>start_rtn:線程的入口函數(shù),即新創(chuàng)建的線程
從該函數(shù)開始執(zhí)行。該函數(shù)只有一個參數(shù),即
arg,返回一個指針
>arg:作為start_rtn的第一個參數(shù)
A成功返回0,出錯時返回各種錯誤碼
18
線程的創(chuàng)建_________
■示例3.1
>編譯:#g++test.cpp-Ipthread
?程序3.1沒有任何輸出。其原因在于主線程先
!!步新創(chuàng)建的線程退出?????
*A什么是主線程?
■示例3.2
?如何能夠等待線程的結(jié)束?pthreadjoin
19
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
20
一線程的終止
■單個線程的三種退出方式
A線程從啟動例程中返回,返回值是線程的退出
II碼IIIIIIIIII
??線程被同一進(jìn)程中的其他線程取消j?
>線程調(diào)用pthread_exit函數(shù)
21
pthreadexit函數(shù)
■該函數(shù)讓線程退出1,1
#include<pthread.h>
voidpthread_exit(void*rval_ptr);
■參數(shù)
>rval_ptr:與線程的啟動函數(shù)類似,該指針將
傳遞給pthread_join函數(shù)
22
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
23
=pjiirgadioin函數(shù)
■該函數(shù)用芋等,待某個線程終止1I
■函數(shù)原型.............................
#include<pthread.h>
intpthreadjoin(pthread_tthread,
void**rval_ptr);
■調(diào)用該函數(shù)的線程將一直阻塞,直到指定
的線程調(diào)用pthread_exit、從啟動例程中返
回、被取消
24
PihjrgadJoin函數(shù)
intpthreadjoin(pthread_tthread,void**rval_ptr);
■返回值與參數(shù)
?A成功返回0,否則返回錯誤編號?||[]
>thread:需要等待的線程ID
>rval_ptr:
3■若線程從啟動例程返回,rval_ptr將包含返回碼1
■若線程由于pthread_exit終止,rval_ptr即pthread_exit的參數(shù)
■若線程被取消,由rval_pt「指定的內(nèi)存單元就置為
PTHREAD_CANCELED
■若不關(guān)心線程返回值,可將該參數(shù)設(shè)置為NULL
25
PihjrgadJoin函數(shù)
■為什么pthread_join的第二個參數(shù)類型是指
針的指針?
I?指針的指針基本原理?傳值與傳指針的區(qū)別?
,>pthread_exit的一個目標(biāo)是,把一個指針傳遞
給pthread」oin函數(shù)
Apthread」oin函數(shù)的思路是:通過參數(shù)的返回
值,將該指針值返回給pthread_join的調(diào)用者
?示州3.31????????
>示例3.4
26
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
27
□threadcancel函數(shù)
■線程調(diào)用該函數(shù)可以取消同一進(jìn)程中的其
他線程,即讓線程終止
■函數(shù)原型IIIIIIII
#include<pthread.h>
intpthread_cancel(pthread_ttid);
■參數(shù)與返回值
>tid:需要取消的線程ID
A成功返回0,出錯返回錯誤編號
28
□threadcancel函數(shù)
■在默認(rèn)情況下,pthread_cancel函數(shù)會使
得線程ID等于tid的線程,如同其調(diào)用了參
數(shù)為PTHREAD_CANCELED的
pthread_exit(示例3.5)
;■線程可以選擇忽略取消方式或者控制取消
方式,將在后面討論
■pthread_cancel并不等待線程終止,它僅
僅是提由請求
29
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
30
pthreaddetach函數(shù)
■在默認(rèn)情況下,線程的終止?fàn)顟B(tài)會保存到
對該線程調(diào)用pthread_join
■若線程已經(jīng)處于分離狀態(tài),線程的底層存
儲資源可以在線程終止時立即被收回
■當(dāng)線程被分離時,并不能用pthread_join函
數(shù)等待它的終止?fàn)顟B(tài),止匕時pthread_join返
回EINVAL
■pthread_detach函數(shù)可以使線程進(jìn)入分離
狀態(tài)一
31
pthreaddetach函數(shù)
■函數(shù)原型I11,111?
#include<pthread.h>
intpthread_detach(pthread_ttid);
■參數(shù)與返面值一
>tid:進(jìn)入分離狀態(tài)的線程的ID
A成功返回0,出錯返回錯誤編號
■示例3.6
■若pthread_join比pthread_detach先調(diào)用,
也能獲取到退出信息一
32
線程的創(chuàng)建與終止
■pthread_create函數(shù)
■pthread_exit函數(shù)
■pthread_join函數(shù)
■pthread_cancel函數(shù)
■pthread_detach函數(shù)
33
?線程的基本概念
?線程的創(chuàng)建與終止II
?線程創(chuàng)建的封裝111
?線程的同步
-線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
線程創(chuàng)建的封裝
■基于對象的封裝
■面向?qū)ο蟮姆庋b111
■基于模板的面向?qū)ο蟮姆庋b
■基于接口的封裝I11
■基于模板的面向方面的封裝
■基于接口的再封裝
基本對象的封裝
■每次調(diào)用pthread_create很繁瑣,能否簡化
線程的創(chuàng)建工作......................
■示例3.7
>為什么使用static函數(shù)?................
|?為什么需要傳遞this指針?
>StartFunctionOfThread是private的,為什么能
司1夠被調(diào)用?11,11,11
?A能否封裝變化點?IIIIIII
36
面向?qū)ο蟮姆庋b
■示例3.8
°X為什么析構(gòu)是虛的?........................
?》能否封裝變化點?............................
??耦合度如何??.........................
;下A如何理解繼承關(guān)系耦合度高?
?耦合于接口、耦合于實現(xiàn)
*.?■在3.8中,只能通過創(chuàng)建線程的方式執(zhí)行業(yè)務(wù)邏輯
■若現(xiàn)在需要通過創(chuàng)建進(jìn)程的方式執(zhí)行業(yè)務(wù)邏輯,該
怎么辦
基于模板的面向?qū)ο蟮姆庋b
■示例3.9
A基于模板的靜態(tài)多態(tài)................
>關(guān)鍵在于理清模板參數(shù)的演繹過程
基于接口的封裝
■不同的線程,通常處理不同的事情,即業(yè)
務(wù)功能.......................
■如何對此變化點(執(zhí)行不同業(yè)務(wù)功能)進(jìn)
行封裝
■示例3.10
■實現(xiàn)了線程具體業(yè)務(wù)功能的裝配
接口的封裝
■目前是以創(chuàng)建線程的方式執(zhí)行業(yè)務(wù)功能,
如果需要創(chuàng)建進(jìn)程的方式執(zhí)行業(yè)務(wù)功能,
又當(dāng)如何?
■如何對此變化點(創(chuàng)建不同的執(zhí)行體)進(jìn)
行封裝?
■示例3.11
r實現(xiàn)了執(zhí)行體的裝配、業(yè)務(wù)功能的裝配
■本課程的執(zhí)行體創(chuàng)建模型,以3.11為基礎(chǔ)
,但后續(xù)還有更多的改造
基于接口的封裝
■基于接口的編程模式,更有利于裝配
A在不改變處理類源代碼的情況下,可以自由組
合
A繼承是一種緊耦合的關(guān)系
.%■耦合于實現(xiàn)
■耦合于接口
?而基于接口的編程模式,僅耦合于接口
41
基于模板的面向方面的封裝
■示例332...........................I
■為什么需要CLTypeSaver?
■為什么CLThread沒有類模板參數(shù)????
■當(dāng)需要擴(kuò)展時,即創(chuàng)建不同類型執(zhí)行體,執(zhí)行不
.同業(yè)務(wù)邏輯時,只需要新增加基類而不是派生類
■每個模板參數(shù),即基類,代表一個方面??
■創(chuàng)建線程還是進(jìn)程,執(zhí)行何種業(yè)務(wù)邏輯,甚至協(xié)
調(diào)器本身均可以裝配
基于接口的再封裝
■在3.10示例中,做到了不同執(zhí)行體、不同
業(yè)務(wù)邏輯的裝配,能否像3.12,做到協(xié)調(diào)
器的裝配?..................
■創(chuàng)建完執(zhí)行體之后,是否可以不立即執(zhí)行
業(yè)務(wù)邏輯,這個流程能裝配嗎?
■示例3.13
?線程的基本概念
?線程的創(chuàng)建與終止II
?線程創(chuàng)建的封裝111
.線程的同步
-線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
一線程的同步
■緩程向步加赧念.................I
、互斥量.............................
、讀寫鎖.............................
■條件變量
45
線程同步的概念
,為什么需萋同'步.............I
A對同一個存儲單元,至少存在兩個執(zhí)行體,其
一讀該單元,另一寫該單元,則需要同步,避
免不一致性
A在處理器架構(gòu)中,對內(nèi)存單元的修改,可能需
要多個總線周期,因此讀操作和寫操作有可能
交織在一起
46
線程同步的概念
■假設(shè)讀操作需要
ThreadAThreadB
一個總線周期
■寫操作需要兩個read
總線周期
write3
■線程B和線程A沖time
突
write,
47
解決上述問題的方法
■使用鎖,以保證共享ThreadAThreadB
存儲一次只能被一個read
線程訪問III
■說明獲取、釋放鎖的
過程
read
48
線程同步的概念
ThreadAThreadBContentsofi
■通常,對一個存儲
fetchiintoregister
單元的訪問,要經(jīng)5
(registet-5)
歷三個步驟
incrementthe
contentsoffetchiintoregister
>將內(nèi)存單元中的數(shù)5
theregister(register=5)
據(jù),讀入寄存器(register=6)
time
A對寄存器中的值進(jìn)storethecontentsincrementthe
oftheregistercontentsof
6
行運算intoitheregister
(rcgister^6)(register06)
?將寄存器中的值,
storethecontents
寫回內(nèi)存單元oftheregister
intoi
■無鎖時的情況(register=6)
49
線程同步的概念
■單線程的程序,需要對存儲同步訪問嗎?
■若需要,能用鎖的機(jī)制嗎?
50
線程同步
■線程同步的概念
■互斥量II
■讀寫鎖II
■條件變量
51
____________互斥量
■可以通過使用pthread的互斥接口保護(hù)數(shù)據(jù),
1確保同一時間里只有q個線程訪問數(shù)據(jù)I
■互斥量mutex,本質(zhì)上就是一把鎖11
I>在訪問共享資源前,對互斥量進(jìn)行加鎖I
?在訪問宛成耳釋角互斥量上的四??I
A對互斥量進(jìn)行加鎖后,任何其他試圖再次對互
斥量加鎖的線程將會被阻塞,直到鎖被釋放
52
互斥量的初始化
■互斥量在使用前,必須要對互斥量進(jìn)行初始
化
,■函數(shù)原型................................
#include<pthread.h>
intpthread_mutex_init(pthread_mutex_t*mutex,
constpthread_mutexattr_t*attr);
■參數(shù)與返回值一一
>mutex:即互斥量,類型是pthread_mutex_t
1:1注意:mutex必須指向有效而內(nèi)存區(qū)域
53
互斥量的初始化
intpthread_mutex_init(pthread_mutex_t*mutex,
constpthread_mutexattr_t*attr);
■參數(shù)與返回值....................I
>attr:設(shè)置互斥量的屬性,通??刹捎媚J(rèn)屬性,
即可將attr設(shè)為NULL。后面再討論互斥量的屬性
?成功返回0,出錯返回錯誤碼
54
互斥量的銷毀_________
■互斥量在使用完畢后,必須要對互斥量進(jìn)行
銷毀,以釋放資源
,■函數(shù)原型.............................
#include<pthread.h>
intpthread_mutex_destroy(
pthread_mutex_t*mutex);
J參數(shù)與返回值一".
>mutex:即互斥量
A成功返回0,出錯返回錯誤碼
55
互斥量的加鎖和解鎖操作
■在對共享資源訪問之前和訪問之后,需要對
互斥量進(jìn)行加鎖和解鎖操作
■「函數(shù)原型IIIIIIIII
#include<pthread.h>
intpthread_mutexjock(pthread_mutex_t*mutex);
Intpthread_mutex_unIock(
pthread_mutex_t*mutex);
■回憶鎖的語義
56
嘗試鎖
■當(dāng)使用pthread_mutex_lock時,若已被加鎖,則
調(diào)用線程將被防塞??挫修k法讓線程不阻塞,
即實現(xiàn)非阻塞的語義??????
■函數(shù)景型1........................
#include<pthread.h>
intpthread_mutex_trylock(pthread_mutex_t*mutex);
?調(diào)用該函數(shù)時,若互斥量未加鎖,則鎖住該互斥
量,返回0;若互斥量已加鎖,則函數(shù)直接返回
失敗,即EBUSY
57
互斥量的操作順序
■定義一個互斥量pthread_mutex_t
■調(diào)用pthread_mutexjnit初始化互斥量
■調(diào)用pthread_mutex_lock或者
pthread_mutex_tryplock對互斥量進(jìn)行力口鎖
慧操作I',"!1,?,,,
■調(diào)用pthread_mutex_unlock對互斥量解鎖
?調(diào)用pthread_mutex_destroy車肖毀互斥量
■示例3.14(在示例3.11基礎(chǔ)之上)
58
CLLOQ的改進(jìn)
■2.27示例中,CLLog的實現(xiàn)不是線程安全
?的................................
?X寫文件時的不安全?????
>創(chuàng)建CLLog唯一對象時的不安全
a-示例3.25(在2.27基礎(chǔ)之上)((
解決了寫文件時的不安全問題,1
■示例3.26(在3.25基礎(chǔ)之上)
>保證了多線程環(huán)境下只會創(chuàng)建一個對象
CLLOQ的改進(jìn)________
■示例3.26存在的問題1111
ACLLog類型的對象只會被創(chuàng)建一次,其后都將
是讀操作
1A但每次讀都需要加鎖、解鎖,效率不高?
mA能否讓后續(xù)的讀操作,不再加鎖
■示例427.........................................
"A雙檢測機(jī)制1111,111
>m_pLog為什么是volatile?
volatile變量
■volatile變量:一般在多線程中使用的比較
多
?例如有一個intx,有兩個線程都要對其讀寫
?有些編譯器或CPU會將x保存在寄存器中,讀
的時候直接讀取寄存器中的內(nèi)容,而不是真實
的x在內(nèi)存中的內(nèi)容
A線程1,對X進(jìn)行加1操作,止匕時內(nèi)存中X的值為
2
A線程2想讀X,結(jié)果從寄存器中讀出1
?給變量加上volatile,指示程序每次讀寫變量都
必須從內(nèi)存中讀取,不要進(jìn)行緩存(寄存器)
互斥量的封裝_________
■每次使用互斥量都需要調(diào)用pthread_mutexjnit
和pthread_mutex_destroy鹵數(shù),能否簡化
■示例3.15(在示例3.11基礎(chǔ)之上)
互斥量的封裝
■獲取鎖之后,一定要釋放鎖
■但是有時候鎖的釋放并不容易被控制1
■示例3.16(在示例3.11基礎(chǔ)之上)
??為什么主線程被阻塞?
?在mutex.Lock()和mutex_Unlock()之間若存在
復(fù)雜的函數(shù)調(diào)用,異常處理又當(dāng)如何?
A每次訪問臨界區(qū),都需要顯示調(diào)用加鎖和解鎖,
能否簡化
63
臨界區(qū)的封裝_________
■示例3.17(在示例3.11基礎(chǔ)之上)
■無論是異常退出還是中途調(diào)用return退出,
'都能保證解鎖?...................
■互斥量的不同范圍,能提供不同程度的互
斥
’》類級別的(static的互斥量)
?對象級別的(普通數(shù)據(jù)成員的互斥量)
線程同步
,庚程向步加赧念111
’?亙斥量..............
■讀寫鎖..............
■條件變量
65
___________________________
■讀寫鎖與互斥量類似,不過讀寫鎖允許更高的并
I行性..................................
■互斥量只有兩種狀態(tài):鎖住、不加鎖
■讀苛鎖三種狀態(tài)
1>讀模'式下方口鎖決態(tài).........................
7寫模式下加鎖狀態(tài)....................
I>不加]鎖狀申[]][]]I[
■一次只有一個線程可以占有寫模式的讀寫鎖、但
多個線程可以同時占用讀模式的讀寫鎖
66
________________
■當(dāng)讀寫鎖是寫加鎖狀態(tài)時,解鎖之前,所
有試圖對這個鎖加鎖的線程都會被阻塞
■當(dāng)讀寫鎖是讀加鎖狀態(tài)時,所有試圖以讀
模式對它進(jìn)行加鎖的線程,都可以得到訪
問權(quán),但以寫模式進(jìn)行加鎖時,它必須阻
塞直到所有的線程釋放讀鎖
■考慮:如何在互斥量的基礎(chǔ)之上,實現(xiàn)單
寫多讀鎖?
■示例3.18(在示例3.11基礎(chǔ)之上)
67
讀寫鎖API
■與互斥量一樣,讀寫鎖在使用之前,必須要初始
化;使用之后,必須要銷毀iiii
■函數(shù)原型..................................
#include<pthread.h>
intpthread_rwlock_init(pthread_rwlock_t*rwlock,const
pthread_rwlockattr_t*attr);
intpthread_rwlock_destroy(pthread_rwlock_t*rwlock);
■返回值
A成功返回0,否則返回錯誤編號
68
讀寫鎖API
intpthread_rwlock_init(pthread_rwlock_t
*rwlock,constpthread_rwlockattr_t*attr);
intpthread_rwlock_destroy(pthread_rwlock_t
*rwlock);
?參數(shù)'............................
>rwlock:讀寫鎖
>attr:讀寫鎖屬性,若用默認(rèn)屬性,可設(shè)置為
NULLo將在后面討論相關(guān)屬性
69
pthreadFW!OQK1rdiock函數(shù)
■該函數(shù)用于鎖定讀鎖1111
■函數(shù)原型.............................
#include<pthread.h>
intpthread_rwlock_rdlock(pthread_rwlock_t
*rwlock);
■參數(shù)與返回值
>rwlock:讀寫鎖
?成功返回0,否則返回錯誤編號
70
pjh迨adrwlocj<wrlock函數(shù)
■該函數(shù)用于鎖定寫鎖1111-
■函數(shù)原型.........................
#include<pthread.h>
intpthread_rwlock_wrlock(pthread_rwlock_t
*rwlock);
■參數(shù)與返回值
>rwlock:讀寫鎖
?成功返回0,否則返回錯誤編號
71
□threadrwlockunlock函數(shù)
■該函數(shù)用于解除讀鎖或者寫鎖1'
■函數(shù)原型.........................
#include<pthread.h>
intpthread_rwlock_unlock(pthread_rwlock_t
*rwlock);
■參數(shù)與返回值
>rwlock:讀寫鎖
?成功返回0,否則返回錯誤編號
72
一嘗試讀寫鎖函數(shù)
-該兩個函數(shù)分別用于嘗試獲取讀鎖、寫鎖.
■函數(shù)原型..............................11
#include<pthread.h>
intpthread_rwlock_tryrdlock(pthread_rwlock_t*rwlock);
intpthread_rwlock_trywrlock(pthread_rwlock_t*rwlock);
■參數(shù)與返回值IIIIIII!
>rwlock:讀寫鎖
A成功返回0,否則返回錯誤編號??梢垣@取鎖時,函數(shù)
返回0;否則返回錯誤EBUSY
73
線程同步
,庚程向步加赧念111
’?亙斥量..............
■讀寫鎖..............
■條件變量
74
■現(xiàn)有一需求,線程A先執(zhí)行某操作后,線程
B才能執(zhí)行另一操作,該如何實現(xiàn)?
■條件變量與互斥量一起使用時,允許線程
以無競爭的方式等待特定條件的發(fā)生
■與互斥量類似,條件變量也需要初始化和
銷毀
75
條件變量的初始化和銷毀
■函數(shù)原型
#include<pthread.h>
intpthread_cond_init(pthread_cond_t*cond,
pthread_condattr_t*attr);
intpthread_cond_destroy(pthread_cond_t*cond);
■參數(shù)和返回值???????
>cond:條件變量
.>attr:條件變量屬性,若為NULL,則使用默認(rèn)屬性
?成功返回0,出錯返回錯誤編號
76
一等待條件的發(fā)生
■pthread_cond_wait函數(shù)將使調(diào)用線程進(jìn)入阻塞
狀態(tài),直到條件為真
■函數(shù)原型
#include<pthread.h>
intpthread_cond_wait(pthread_cond_t*cond,
pthread_mutex_t*mutex);
■參數(shù)與返回值一一
>cond:條件變量
>mutex:互斥量
A成功返回0,否則返回錯誤編號
77
一等待條件的發(fā)生
■為什么pthread_cond_wait需要互斥量
?在調(diào)用pthread_cond_wait前,需要使互斥量
處于鎖住狀態(tài)
>這樣pthread_cond_waitBi數(shù),可以以原子的
方式,將調(diào)而線程放到等待條件的線程列表上
■pthread_cond_wait函數(shù)的特殊操作
?在線程阻塞前,調(diào)用pthread_mutex_unlock
BA在線程喚醒后,調(diào)用pthread_mutex_lock?
78
一等待條件的發(fā)生
■等待線程的操作順序1111
?調(diào)用pthread_mutex_lock
?調(diào)用pthread_cond_wait
?調(diào)用pthread_mutex_unlock
79
一使等待的條件為真
■pthread_cond_signal和
pthread_cond_broadcast可以通知等待的線程,
條件已盔滿足「j1
■pthread_cond_signal喚醒某一個等待該條件的
「線程r11111111
■pthread_cond_broadcast喚醒等待該條件的所
有線程——
80
—等待條件為真
,■函數(shù)原型...........................I
#include<pthread.h>
intpthread_cond_signal(pthread_cond_t*cond);
intpthread_cond_broadcast(pthread_cond_t*);
I-參金專返回值,,,,,,,
>cond:條件變量
A成功返回0,否則返回錯誤編號
條件變量的封裝
■示例3.19(在示例3.11基礎(chǔ)之上)
1a為什么主線程陷入阻塞狀態(tài)而不返回?
>為什么子線程加入sleep后正常?
82
___________條件變量___________
-上例由錯加原I因..............
?子線程調(diào)用pthread_cond_signal后,主線程才
調(diào)用pthread_cond_wait進(jìn)入阻塞狀態(tài)
,A這樣,主線程就一直無法被喚醒?
■解決方案
A示例3.20(在示例3.11基礎(chǔ)之上)
83
■等待線程
>調(diào)用pthread_mutex_lock
>While(判斷條件)pthread_cond_wait
■重復(fù)檢查條件是由于線程可能不是被pthread_cond_signal喚
醒,可能是由信號等喚醒(futex)
>pthread_mutex_unlock
■被等待線程一???????
>調(diào)用pthread_mutex_lock
.>修改條件?一?7??????
>調(diào)用pthread_mutex_unlock
>調(diào)用pthread_mutex_broadcast等
84
___________條件變量___________
■P0SIX.1說明:pthread_cond_broadcast
等函數(shù)的調(diào)用無需考慮錮用線”是否擁有
鎖,并建議在在lock和unlock以外的區(qū)域調(diào)
?用「用什么?????????
[假設(shè)率統(tǒng)|有J線中和?線岸2((((
矗A線程1獲取mutex,在進(jìn)行數(shù)據(jù)處理的時候,線
程2(等待線程)也想獲取mutex,但是此時被
線程1所占用,線程2進(jìn)入休眠,等待mutex被
釋放
85
條件變量
A線程1做完數(shù)據(jù)處理后,調(diào)用
pthread_cond_signal喚醒等待隊歹U中某個線程,
在本例幣也就是線程2。線程1在調(diào)用
pthread_mutex_unlocklil,因為系統(tǒng)調(diào)度的原
因,線程2獲取使用CPU的權(quán)利,那么它就想
要開始處理數(shù)據(jù),但是在開始處理之前,
mutex必須被獲取,線程1正在使用mutex,所
以線程2被迫再次進(jìn)入休眠
?然后就是線程1執(zhí)行pthread_mutex_unlock()
后,線程2方能被再次喚醒廠"
?十分低效
86
事件的封裝__________
■條件變量的處理比較復(fù)雜,需要有flag變量、
1固定的函數(shù)調(diào)用序列等等?iiii
'能否簡化條件變量的使用..............
■封裝的思路:iI..................
>Windows的事件機(jī)制
:?讓一個線程等待某一個事件的發(fā)生??
■示例3.21(在示例3.11基礎(chǔ)之上)
>為什么m_Flag是volatile的
87
一線程的同步
■緩程向步加赧念.................I
、互斥量.............................
、讀寫鎖.............................
■條件變量
88
?線程的基本概念
?線程的創(chuàng)建與終止II
?線程創(chuàng)建的封裝111
.線程的同步
I線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
線程創(chuàng)建的再封裝
■一個CLThread類的對象,應(yīng)該只對應(yīng)一個
。線程.............................
■用戶如果按照如下方式使用,會有什么后
果?
CLThread*p=..................;
p->Run();
p->Run();
線程創(chuàng)建的再封裝
■前一次創(chuàng)建的線程,可能無法再被控制。
例如:m_ThreadlD僅為剛創(chuàng)建線程的ID,
調(diào)用WsdtForDeath,將無法等待上一個線
程的結(jié)束????????
■如何解決,以防止在一個CLThread對象上
,多次調(diào)用Run方法?一‘||
■示例3.22(在示例3.11基礎(chǔ)之上)
線程創(chuàng)建的再封裝
■通常情況下,CLThread類及
CLExecutiveFunctionProvider派生類的對
象,應(yīng)從堆中分配。為什么不是棧上?
■從堆中分配,就需要顯式的釋放,能否簡
化?能否讓類的使用者,只分配對象,而
不用調(diào)用delete?
■示例3.23(在示例3.22基礎(chǔ)之上)
線程創(chuàng)建的再封裝
■在有些情況下,新線程的創(chuàng)建者,可能不
需要等待新線程死亡,即不調(diào)用
WaitForDeath
■這樣3.23的釋放對象方式將失效???
■示例3.24(在示例3.23基礎(chǔ)之上)
?增加一個標(biāo)識,讓用戶指定他是否需要等待新
線程死亡
線程創(chuàng)建的再封裝
1
■產(chǎn)生異常的原因在于:111'V
>新線程在主線程調(diào)用WaitForDeath之前就已經(jīng)退出了
>甚至有可能在主線程剛調(diào)用完pthread_create之后,
就退出了
■解決辦法:?????????
>需要保證在Run方法退出之前,新線程不會死亡
A若用戶選擇了不等待新線程死亡,則他就不應(yīng)該再調(diào)
fflWaitForDeath
?另外,從語義上講,Run方法返回前,應(yīng)保證新線程
確實已經(jīng)被創(chuàng)建了
A示例3.28(在示例3.24基礎(chǔ)之上)
?線程的基本概念
?線程的創(chuàng)建與終止II
?線程創(chuàng)建的封裝111
.線程的同步
g線程創(chuàng)建的再封裝
■Windows消息在Linux的重現(xiàn)
Windows消息在Linux的重現(xiàn)
■在windows中,進(jìn)行線程之間的通信十分
簡便。Windows系統(tǒng)為每個線程都配備了
二個消息隊列..................
■調(diào)用PostThreadMessage函數(shù),可以向一
1個線程發(fā)送消息??????
■調(diào)用GetMessage函數(shù),可以從消息隊列中
獲取一個消息
生產(chǎn)者/消費者模型
■消息隊列及機(jī)制,是一種典型的生產(chǎn)者/消
費者模型應(yīng)用。
■發(fā)送消息的線程(生產(chǎn)者):將消息投入
到消息隊列后,即返回
■消息的接收線程(消費者):一直處于阻
塞等待狀態(tài),直到有線程將消息投入到消
息隊列中
■我們的目標(biāo):建立一個自定義的消息隊列
,以實現(xiàn)同一進(jìn)程內(nèi)線程之間的通信
Windows消息在Linux的重現(xiàn)
■梏息的封裝111111-
■自定義消息隊列的實現(xiàn)1,11
■消息循環(huán)機(jī)制的封裝11111
■創(chuàng)建線程與消息循環(huán)的結(jié)合III
■簡單的名字服務(wù)..................
■使用的簡化
Windows消息在Linux的重現(xiàn)
■消息的封裝.....................?
■自定義消息隊列的實現(xiàn)1,11
■消息循環(huán)機(jī)制的封裝..............
■創(chuàng)建線程與消息循環(huán)的結(jié)合,11
■簡單的名字服務(wù)..................
■使用的簡化
消息的封裝__________
■Windows的線程消息:
BOOLWINAPIPostThreadMessage(
DWORDidThread,
UINTMsg,
WPARAMwParam,
LPARAMIParam
);
■Windows的消息包含了線程ID,以及兩個自定義
參數(shù),不符合面向?qū)ο蟮乃枷?/p>
■需要建立起有關(guān)消息的繼承體系
消息的繼承體系
■示例3.29
■CLMessage是對消息的抽象,僅包含了消
息的ID
■線程之間發(fā)送的具體消息,需要從??
CLMessage派生,并定義屬于該消息自己
的參數(shù)
Windows消息在Linux的重現(xiàn)
■消息的封裝111111-
■自定義消息隊列的實現(xiàn)||||
■消息循環(huán)機(jī)制的封裝..............
■創(chuàng)建線程與消息循環(huán)的結(jié)合111
■簡單的名字服務(wù)..................
■使用的簡化
自定義消息隊列的實現(xiàn)
■隊列本身采用STL庫中的queue類,該類型
的隊列能自動增長................
■必須以線程安全的方式,將消息放入到隊
列中,然后通知等待的線程消息已到達(dá)
■通知的機(jī)制可以采用CLEvent類,但3.21
示例中的CLEvent必須改造
■示例3.30
自定義消息隊列的實現(xiàn)
■CLMessageQueue的實現(xiàn)
■示例3.31
■在上例中,采用STL的queue實現(xiàn)了消息隊
歹U]??????????
■也可以采用其他方式實現(xiàn),例如管道、網(wǎng)
絡(luò)通信、自定義的隊列等等
■如何封裝這一變化點?它們之間是否有共
通的部分(均為生產(chǎn)者/消費者模型應(yīng)用)
Windows消息在Linux的重現(xiàn)
■消息的封裝111111-
■自定義消息隊列的實現(xiàn)||||
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 中考作文指導(dǎo):《給“普通素材”加點“料”》教學(xué)設(shè)計
- 二零二五年度房屋置換與社區(qū)養(yǎng)老服務(wù)體系合同
- 二零二五年度酒店客房安全免責(zé)協(xié)議及賓客責(zé)任說明
- 二零二五年度鉆機(jī)銷售及配件供應(yīng)合作協(xié)議
- 二零二五年度財務(wù)人員離職保密條款及離職后保密協(xié)議
- 《推理》教學(xué)設(shè)計-2024-2025學(xué)年二年級下冊數(shù)學(xué)人教版
- 二零二五年度餐館服務(wù)員食品安全責(zé)任合同
- 2025年度酒店與宗教活動組織者住宿協(xié)議合同
- 2025年度旅游度假區(qū)合作開發(fā)與品牌建設(shè)協(xié)議
- 二零二五年度地攤電商運營與推廣合同
- 2024-2025學(xué)年第二學(xué)期(2025春季學(xué)期)學(xué)校工作計劃(附2月-6月安排表)
- 新人教版五年級小學(xué)數(shù)學(xué)全冊奧數(shù)(含答案)
- 志愿服務(wù)證明(多模板)
- 人教版三年級下冊體育與健康教案(全冊教學(xué)設(shè)計)
- DB61∕T 5006-2021 人民防空工程標(biāo)識標(biāo)準(zhǔn)
- 土壤學(xué)習(xí)題與答案
- 產(chǎn)品結(jié)構(gòu)設(shè)計(課堂PPT)
- 第九課_靜止的生命
- 尖尖的東西我不碰(課堂PPT)
- 工程勘察和設(shè)計承攬業(yè)務(wù)的范圍
- 數(shù)字化影像與PACS教學(xué)大綱
評論
0/150
提交評論