Linux環(huán)境高級編程_第1頁
Linux環(huán)境高級編程_第2頁
Linux環(huán)境高級編程_第3頁
Linux環(huán)境高級編程_第4頁
Linux環(huán)境高級編程_第5頁
已閱讀5頁,還剩115頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論