Linux環境高級編程_第1頁
Linux環境高級編程_第2頁
Linux環境高級編程_第3頁
Linux環境高級編程_第4頁
Linux環境高級編程_第5頁
已閱讀5頁,還剩115頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

Linux環境高級編程

李林

電子科技大學軟件學院

第三講線程的封裝

李林

電子科技大學軟件學院

?線程的基本概念

?線程的創建與終止II

?線程創建的封裝111

.線程的同步

-線程創建的再封裝

■Windows消息在Linux的重現

第二講線程的封裝

.線程的基本概念1111

?線程的創建與終止111

?線程創建的封裝1,11

.線程的同步IIIII

-線程創建的再封裝

■Windows消息在Linux的重現

—線程的概念_________

■進程的所有信息對該進程的所有線程都是

共享的,包括可執行的程序文本、程序的

I全局內存、堆內存、文件描述符等

■線程獨有的:線程ID、寄存器值、棧、信

.號屏蔽字、errno值、線程私有數據

■典型的UNIX進程,可以看成是只有一個線

程的進程

5

—線程的概念_________

■同進程一樣,每個線程也有一個線程ID

■進程ID在整個系統中是唯一的,但線程ID

不同,線程ID只在它所屬的進程環境中有

?效一?????????

■線程ID的類型是pthread_t,在Linux中的定

義:

A在/usr/include/bits/pthreadtypes.h中

>typedefunsignedlongintpthread_t;

6

■pthread_self函數可以使調用線程獲取自己

的線程后...........................

■函數原型IIIIIIII

#include<pthread.h>

pthread_tpthread_self();

■返回調用線程的線程ID

7

—線程的概念_________

■Linux中使用整型表示線程ID,而其他系統

則不一定

■FreeBSD5.2.1>MacOSX10.3用一個指

向pthread結構的指針來表示pthread_t類型。

■為了移植性,在比較兩個線程ID是否相同

時,可以使用pthread_equal函數

8

pthreadequal^S

■該函數用于比較兩個線程ID是否相同

■函數原型.....................11

#include<pthread.h>

intpthread_equal(pthread_ttid1,pthread_ttid2);

■若相等則返回非0值,否則返回0

9

?線程的基本概念

?線程的創建與終止11

?線程創建的封裝111

.線程的同步

-線程創建的再封裝

■Windows消息在Linux的重現

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

11

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

12

一線程的創建

■pthread_create函數用于創建一個線程

■函數原M..................................................

#include<pthread.h>

intpthread_create(pthread_t*restricttidp,

constpthread_attr_t*restrictattr,

void*(*start_rtn)(void*),

void*restrictarg);

■參數與返回值

>tidp:當pthread_create成功返回時,該函數將線程ID

存儲在tidp指向的內存區域中

13

rest,jet關鍵字________

■restrict關鍵字C99標準引入的,

,.只能用于限定指針..................

B表明指針是訪問一個數據對象的唯一且初始

的方式

resjcj;關鍵字________

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;關鍵字________

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關鍵字

intar[10];

int*restrictrestar=(int*)malloc(1O*sizeof(int));

int*par=ar;

for(intn=0;n<10;n++){

par[n]+=5;

對restar的操作進行優化,

restar[n]+=8

restar[n]+=5;

無法對par的操作優化

Lr[n]*=2;]

par[n]+=8

I什么是編譯單元?

par[n]+=3;

restar[n]+=3;

}

pthreadcrgate函數

■參數與返回值11111

0>attr:用于定制各種不同的線程屬性,將在后

面部分討論。通常可設為NULL,采用默認線

J呈扈性

>start_rtn:線程的入口函數,即新創建的線程

從該函數開始執行。該函數只有一個參數,即

arg,返回一個指針

>arg:作為start_rtn的第一個參數

A成功返回0,出錯時返回各種錯誤碼

18

線程的創建_________

■示例3.1

>編譯:#g++test.cpp-Ipthread

?程序3.1沒有任何輸出。其原因在于主線程先

!!步新創建的線程退出?????

*A什么是主線程?

■示例3.2

?如何能夠等待線程的結束?pthreadjoin

19

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

20

一線程的終止

■單個線程的三種退出方式

A線程從啟動例程中返回,返回值是線程的退出

II碼IIIIIIIIII

??線程被同一進程中的其他線程取消j?

>線程調用pthread_exit函數

21

pthreadexit函數

■該函數讓線程退出1,1

#include<pthread.h>

voidpthread_exit(void*rval_ptr);

■參數

>rval_ptr:與線程的啟動函數類似,該指針將

傳遞給pthread_join函數

22

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

23

=pjiirgadioin函數

■該函數用芋等,待某個線程終止1I

■函數原型.............................

#include<pthread.h>

intpthreadjoin(pthread_tthread,

void**rval_ptr);

■調用該函數的線程將一直阻塞,直到指定

的線程調用pthread_exit、從啟動例程中返

回、被取消

24

PihjrgadJoin函數

intpthreadjoin(pthread_tthread,void**rval_ptr);

■返回值與參數

?A成功返回0,否則返回錯誤編號?||[]

>thread:需要等待的線程ID

>rval_ptr:

3■若線程從啟動例程返回,rval_ptr將包含返回碼1

■若線程由于pthread_exit終止,rval_ptr即pthread_exit的參數

■若線程被取消,由rval_pt「指定的內存單元就置為

PTHREAD_CANCELED

■若不關心線程返回值,可將該參數設置為NULL

25

PihjrgadJoin函數

■為什么pthread_join的第二個參數類型是指

針的指針?

I?指針的指針基本原理?傳值與傳指針的區別?

,>pthread_exit的一個目標是,把一個指針傳遞

給pthread」oin函數

Apthread」oin函數的思路是:通過參數的返回

值,將該指針值返回給pthread_join的調用者

?示州3.31????????

>示例3.4

26

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

27

□threadcancel函數

■線程調用該函數可以取消同一進程中的其

他線程,即讓線程終止

■函數原型IIIIIIII

#include<pthread.h>

intpthread_cancel(pthread_ttid);

■參數與返回值

>tid:需要取消的線程ID

A成功返回0,出錯返回錯誤編號

28

□threadcancel函數

■在默認情況下,pthread_cancel函數會使

得線程ID等于tid的線程,如同其調用了參

數為PTHREAD_CANCELED的

pthread_exit(示例3.5)

;■線程可以選擇忽略取消方式或者控制取消

方式,將在后面討論

■pthread_cancel并不等待線程終止,它僅

僅是提由請求

29

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

30

pthreaddetach函數

■在默認情況下,線程的終止狀態會保存到

對該線程調用pthread_join

■若線程已經處于分離狀態,線程的底層存

儲資源可以在線程終止時立即被收回

■當線程被分離時,并不能用pthread_join函

數等待它的終止狀態,止匕時pthread_join返

回EINVAL

■pthread_detach函數可以使線程進入分離

狀態一

31

pthreaddetach函數

■函數原型I11,111?

#include<pthread.h>

intpthread_detach(pthread_ttid);

■參數與返面值一

>tid:進入分離狀態的線程的ID

A成功返回0,出錯返回錯誤編號

■示例3.6

■若pthread_join比pthread_detach先調用,

也能獲取到退出信息一

32

線程的創建與終止

■pthread_create函數

■pthread_exit函數

■pthread_join函數

■pthread_cancel函數

■pthread_detach函數

33

?線程的基本概念

?線程的創建與終止II

?線程創建的封裝111

?線程的同步

-線程創建的再封裝

■Windows消息在Linux的重現

線程創建的封裝

■基于對象的封裝

■面向對象的封裝111

■基于模板的面向對象的封裝

■基于接口的封裝I11

■基于模板的面向方面的封裝

■基于接口的再封裝

基本對象的封裝

■每次調用pthread_create很繁瑣,能否簡化

線程的創建工作......................

■示例3.7

>為什么使用static函數?................

|?為什么需要傳遞this指針?

>StartFunctionOfThread是private的,為什么能

司1夠被調用?11,11,11

?A能否封裝變化點?IIIIIII

36

面向對象的封裝

■示例3.8

°X為什么析構是虛的?........................

?》能否封裝變化點?............................

??耦合度如何??.........................

;下A如何理解繼承關系耦合度高?

?耦合于接口、耦合于實現

*.?■在3.8中,只能通過創建線程的方式執行業務邏輯

■若現在需要通過創建進程的方式執行業務邏輯,該

怎么辦

基于模板的面向對象的封裝

■示例3.9

A基于模板的靜態多態................

>關鍵在于理清模板參數的演繹過程

基于接口的封裝

■不同的線程,通常處理不同的事情,即業

務功能.......................

■如何對此變化點(執行不同業務功能)進

行封裝

■示例3.10

■實現了線程具體業務功能的裝配

接口的封裝

■目前是以創建線程的方式執行業務功能,

如果需要創建進程的方式執行業務功能,

又當如何?

■如何對此變化點(創建不同的執行體)進

行封裝?

■示例3.11

r實現了執行體的裝配、業務功能的裝配

■本課程的執行體創建模型,以3.11為基礎

,但后續還有更多的改造

基于接口的封裝

■基于接口的編程模式,更有利于裝配

A在不改變處理類源代碼的情況下,可以自由組

A繼承是一種緊耦合的關系

.%■耦合于實現

■耦合于接口

?而基于接口的編程模式,僅耦合于接口

41

基于模板的面向方面的封裝

■示例332...........................I

■為什么需要CLTypeSaver?

■為什么CLThread沒有類模板參數????

■當需要擴展時,即創建不同類型執行體,執行不

.同業務邏輯時,只需要新增加基類而不是派生類

■每個模板參數,即基類,代表一個方面??

■創建線程還是進程,執行何種業務邏輯,甚至協

調器本身均可以裝配

基于接口的再封裝

■在3.10示例中,做到了不同執行體、不同

業務邏輯的裝配,能否像3.12,做到協調

器的裝配?..................

■創建完執行體之后,是否可以不立即執行

業務邏輯,這個流程能裝配嗎?

■示例3.13

?線程的基本概念

?線程的創建與終止II

?線程創建的封裝111

.線程的同步

-線程創建的再封裝

■Windows消息在Linux的重現

一線程的同步

■緩程向步加赧念.................I

、互斥量.............................

、讀寫鎖.............................

■條件變量

45

線程同步的概念

,為什么需萋同'步.............I

A對同一個存儲單元,至少存在兩個執行體,其

一讀該單元,另一寫該單元,則需要同步,避

免不一致性

A在處理器架構中,對內存單元的修改,可能需

要多個總線周期,因此讀操作和寫操作有可能

交織在一起

46

線程同步的概念

■假設讀操作需要

ThreadAThreadB

一個總線周期

■寫操作需要兩個read

總線周期

write3

■線程B和線程A沖time

write,

47

解決上述問題的方法

■使用鎖,以保證共享ThreadAThreadB

存儲一次只能被一個read

線程訪問III

■說明獲取、釋放鎖的

過程

read

48

線程同步的概念

ThreadAThreadBContentsofi

■通常,對一個存儲

fetchiintoregister

單元的訪問,要經5

(registet-5)

歷三個步驟

incrementthe

contentsoffetchiintoregister

>將內存單元中的數5

theregister(register=5)

據,讀入寄存器(register=6)

time

A對寄存器中的值進storethecontentsincrementthe

oftheregistercontentsof

6

行運算intoitheregister

(rcgister^6)(register06)

?將寄存器中的值,

storethecontents

寫回內存單元oftheregister

intoi

■無鎖時的情況(register=6)

49

線程同步的概念

■單線程的程序,需要對存儲同步訪問嗎?

■若需要,能用鎖的機制嗎?

50

線程同步

■線程同步的概念

■互斥量II

■讀寫鎖II

■條件變量

51

____________互斥量

■可以通過使用pthread的互斥接口保護數據,

1確保同一時間里只有q個線程訪問數據I

■互斥量mutex,本質上就是一把鎖11

I>在訪問共享資源前,對互斥量進行加鎖I

?在訪問宛成耳釋角互斥量上的四??I

A對互斥量進行加鎖后,任何其他試圖再次對互

斥量加鎖的線程將會被阻塞,直到鎖被釋放

52

互斥量的初始化

■互斥量在使用前,必須要對互斥量進行初始

,■函數原型................................

#include<pthread.h>

intpthread_mutex_init(pthread_mutex_t*mutex,

constpthread_mutexattr_t*attr);

■參數與返回值一一

>mutex:即互斥量,類型是pthread_mutex_t

1:1注意:mutex必須指向有效而內存區域

53

互斥量的初始化

intpthread_mutex_init(pthread_mutex_t*mutex,

constpthread_mutexattr_t*attr);

■參數與返回值....................I

>attr:設置互斥量的屬性,通常可采用默認屬性,

即可將attr設為NULL。后面再討論互斥量的屬性

?成功返回0,出錯返回錯誤碼

54

互斥量的銷毀_________

■互斥量在使用完畢后,必須要對互斥量進行

銷毀,以釋放資源

,■函數原型.............................

#include<pthread.h>

intpthread_mutex_destroy(

pthread_mutex_t*mutex);

J參數與返回值一".

>mutex:即互斥量

A成功返回0,出錯返回錯誤碼

55

互斥量的加鎖和解鎖操作

■在對共享資源訪問之前和訪問之后,需要對

互斥量進行加鎖和解鎖操作

■「函數原型IIIIIIIII

#include<pthread.h>

intpthread_mutexjock(pthread_mutex_t*mutex);

Intpthread_mutex_unIock(

pthread_mutex_t*mutex);

■回憶鎖的語義

56

嘗試鎖

■當使用pthread_mutex_lock時,若已被加鎖,則

調用線程將被防塞。看殳有辦法讓線程不阻塞,

即實現非阻塞的語義??????

■函數景型1........................

#include<pthread.h>

intpthread_mutex_trylock(pthread_mutex_t*mutex);

?調用該函數時,若互斥量未加鎖,則鎖住該互斥

量,返回0;若互斥量已加鎖,則函數直接返回

失敗,即EBUSY

57

互斥量的操作順序

■定義一個互斥量pthread_mutex_t

■調用pthread_mutexjnit初始化互斥量

■調用pthread_mutex_lock或者

pthread_mutex_tryplock對互斥量進行力口鎖

慧操作I',"!1,?,,,

■調用pthread_mutex_unlock對互斥量解鎖

?調用pthread_mutex_destroy車肖毀互斥量

■示例3.14(在示例3.11基礎之上)

58

CLLOQ的改進

■2.27示例中,CLLog的實現不是線程安全

?的................................

?X寫文件時的不安全?????

>創建CLLog唯一對象時的不安全

a-示例3.25(在2.27基礎之上)((

解決了寫文件時的不安全問題,1

■示例3.26(在3.25基礎之上)

>保證了多線程環境下只會創建一個對象

CLLOQ的改進________

■示例3.26存在的問題1111

ACLLog類型的對象只會被創建一次,其后都將

是讀操作

1A但每次讀都需要加鎖、解鎖,效率不高?

mA能否讓后續的讀操作,不再加鎖

■示例427.........................................

"A雙檢測機制1111,111

>m_pLog為什么是volatile?

volatile變量

■volatile變量:一般在多線程中使用的比較

?例如有一個intx,有兩個線程都要對其讀寫

?有些編譯器或CPU會將x保存在寄存器中,讀

的時候直接讀取寄存器中的內容,而不是真實

的x在內存中的內容

A線程1,對X進行加1操作,止匕時內存中X的值為

2

A線程2想讀X,結果從寄存器中讀出1

?給變量加上volatile,指示程序每次讀寫變量都

必須從內存中讀取,不要進行緩存(寄存器)

互斥量的封裝_________

■每次使用互斥量都需要調用pthread_mutexjnit

和pthread_mutex_destroy鹵數,能否簡化

■示例3.15(在示例3.11基礎之上)

互斥量的封裝

■獲取鎖之后,一定要釋放鎖

■但是有時候鎖的釋放并不容易被控制1

■示例3.16(在示例3.11基礎之上)

??為什么主線程被阻塞?

?在mutex.Lock()和mutex_Unlock()之間若存在

復雜的函數調用,異常處理又當如何?

A每次訪問臨界區,都需要顯示調用加鎖和解鎖,

能否簡化

63

臨界區的封裝_________

■示例3.17(在示例3.11基礎之上)

■無論是異常退出還是中途調用return退出,

'都能保證解鎖?...................

■互斥量的不同范圍,能提供不同程度的互

’》類級別的(static的互斥量)

?對象級別的(普通數據成員的互斥量)

線程同步

,庚程向步加赧念111

’?亙斥量..............

■讀寫鎖..............

■條件變量

65

___________________________

■讀寫鎖與互斥量類似,不過讀寫鎖允許更高的并

I行性..................................

■互斥量只有兩種狀態:鎖住、不加鎖

■讀苛鎖三種狀態

1>讀模'式下方口鎖決態.........................

7寫模式下加鎖狀態....................

I>不加]鎖狀申[]][]]I[

■一次只有一個線程可以占有寫模式的讀寫鎖、但

多個線程可以同時占用讀模式的讀寫鎖

66

________________

■當讀寫鎖是寫加鎖狀態時,解鎖之前,所

有試圖對這個鎖加鎖的線程都會被阻塞

■當讀寫鎖是讀加鎖狀態時,所有試圖以讀

模式對它進行加鎖的線程,都可以得到訪

問權,但以寫模式進行加鎖時,它必須阻

塞直到所有的線程釋放讀鎖

■考慮:如何在互斥量的基礎之上,實現單

寫多讀鎖?

■示例3.18(在示例3.11基礎之上)

67

讀寫鎖API

■與互斥量一樣,讀寫鎖在使用之前,必須要初始

化;使用之后,必須要銷毀iiii

■函數原型..................................

#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);

?參數'............................

>rwlock:讀寫鎖

>attr:讀寫鎖屬性,若用默認屬性,可設置為

NULLo將在后面討論相關屬性

69

pthreadFW!OQK1rdiock函數

■該函數用于鎖定讀鎖1111

■函數原型.............................

#include<pthread.h>

intpthread_rwlock_rdlock(pthread_rwlock_t

*rwlock);

■參數與返回值

>rwlock:讀寫鎖

?成功返回0,否則返回錯誤編號

70

pjh迨adrwlocj<wrlock函數

■該函數用于鎖定寫鎖1111-

■函數原型.........................

#include<pthread.h>

intpthread_rwlock_wrlock(pthread_rwlock_t

*rwlock);

■參數與返回值

>rwlock:讀寫鎖

?成功返回0,否則返回錯誤編號

71

□threadrwlockunlock函數

■該函數用于解除讀鎖或者寫鎖1'

■函數原型.........................

#include<pthread.h>

intpthread_rwlock_unlock(pthread_rwlock_t

*rwlock);

■參數與返回值

>rwlock:讀寫鎖

?成功返回0,否則返回錯誤編號

72

一嘗試讀寫鎖函數

-該兩個函數分別用于嘗試獲取讀鎖、寫鎖.

■函數原型..............................11

#include<pthread.h>

intpthread_rwlock_tryrdlock(pthread_rwlock_t*rwlock);

intpthread_rwlock_trywrlock(pthread_rwlock_t*rwlock);

■參數與返回值IIIIIII!

>rwlock:讀寫鎖

A成功返回0,否則返回錯誤編號。可以獲取鎖時,函數

返回0;否則返回錯誤EBUSY

73

線程同步

,庚程向步加赧念111

’?亙斥量..............

■讀寫鎖..............

■條件變量

74

■現有一需求,線程A先執行某操作后,線程

B才能執行另一操作,該如何實現?

■條件變量與互斥量一起使用時,允許線程

以無競爭的方式等待特定條件的發生

■與互斥量類似,條件變量也需要初始化和

銷毀

75

條件變量的初始化和銷毀

■函數原型

#include<pthread.h>

intpthread_cond_init(pthread_cond_t*cond,

pthread_condattr_t*attr);

intpthread_cond_destroy(pthread_cond_t*cond);

■參數和返回值???????

>cond:條件變量

.>attr:條件變量屬性,若為NULL,則使用默認屬性

?成功返回0,出錯返回錯誤編號

76

一等待條件的發生

■pthread_cond_wait函數將使調用線程進入阻塞

狀態,直到條件為真

■函數原型

#include<pthread.h>

intpthread_cond_wait(pthread_cond_t*cond,

pthread_mutex_t*mutex);

■參數與返回值一一

>cond:條件變量

>mutex:互斥量

A成功返回0,否則返回錯誤編號

77

一等待條件的發生

■為什么pthread_cond_wait需要互斥量

?在調用pthread_cond_wait前,需要使互斥量

處于鎖住狀態

>這樣pthread_cond_waitBi數,可以以原子的

方式,將調而線程放到等待條件的線程列表上

■pthread_cond_wait函數的特殊操作

?在線程阻塞前,調用pthread_mutex_unlock

BA在線程喚醒后,調用pthread_mutex_lock?

78

一等待條件的發生

■等待線程的操作順序1111

?調用pthread_mutex_lock

?調用pthread_cond_wait

?調用pthread_mutex_unlock

79

一使等待的條件為真

■pthread_cond_signal和

pthread_cond_broadcast可以通知等待的線程,

條件已盔滿足「j1

■pthread_cond_signal喚醒某一個等待該條件的

「線程r11111111

■pthread_cond_broadcast喚醒等待該條件的所

有線程——

80

—等待條件為真

,■函數原型...........................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基礎之上)

1a為什么主線程陷入阻塞狀態而不返回?

>為什么子線程加入sleep后正常?

82

___________條件變量___________

-上例由錯加原I因..............

?子線程調用pthread_cond_signal后,主線程才

調用pthread_cond_wait進入阻塞狀態

,A這樣,主線程就一直無法被喚醒?

■解決方案

A示例3.20(在示例3.11基礎之上)

83

■等待線程

>調用pthread_mutex_lock

>While(判斷條件)pthread_cond_wait

■重復檢查條件是由于線程可能不是被pthread_cond_signal喚

醒,可能是由信號等喚醒(futex)

>pthread_mutex_unlock

■被等待線程一???????

>調用pthread_mutex_lock

.>修改條件?一?7??????

>調用pthread_mutex_unlock

>調用pthread_mutex_broadcast等

84

___________條件變量___________

■P0SIX.1說明:pthread_cond_broadcast

等函數的調用無需考慮錮用線”是否擁有

鎖,并建議在在lock和unlock以外的區域調

?用「用什么?????????

[假設率統|有J線中和?線岸2((((

矗A線程1獲取mutex,在進行數據處理的時候,線

程2(等待線程)也想獲取mutex,但是此時被

線程1所占用,線程2進入休眠,等待mutex被

釋放

85

條件變量

A線程1做完數據處理后,調用

pthread_cond_signal喚醒等待隊歹U中某個線程,

在本例幣也就是線程2。線程1在調用

pthread_mutex_unlocklil,因為系統調度的原

因,線程2獲取使用CPU的權利,那么它就想

要開始處理數據,但是在開始處理之前,

mutex必須被獲取,線程1正在使用mutex,所

以線程2被迫再次進入休眠

?然后就是線程1執行pthread_mutex_unlock()

后,線程2方能被再次喚醒廠"

?十分低效

86

事件的封裝__________

■條件變量的處理比較復雜,需要有flag變量、

1固定的函數調用序列等等?iiii

'能否簡化條件變量的使用..............

■封裝的思路:iI..................

>Windows的事件機制

:?讓一個線程等待某一個事件的發生??

■示例3.21(在示例3.11基礎之上)

>為什么m_Flag是volatile的

87

一線程的同步

■緩程向步加赧念.................I

、互斥量.............................

、讀寫鎖.............................

■條件變量

88

?線程的基本概念

?線程的創建與終止II

?線程創建的封裝111

.線程的同步

I線程創建的再封裝

■Windows消息在Linux的重現

線程創建的再封裝

■一個CLThread類的對象,應該只對應一個

。線程.............................

■用戶如果按照如下方式使用,會有什么后

果?

CLThread*p=..................;

p->Run();

p->Run();

線程創建的再封裝

■前一次創建的線程,可能無法再被控制。

例如:m_ThreadlD僅為剛創建線程的ID,

調用WsdtForDeath,將無法等待上一個線

程的結束????????

■如何解決,以防止在一個CLThread對象上

,多次調用Run方法?一‘||

■示例3.22(在示例3.11基礎之上)

線程創建的再封裝

■通常情況下,CLThread類及

CLExecutiveFunctionProvider派生類的對

象,應從堆中分配。為什么不是棧上?

■從堆中分配,就需要顯式的釋放,能否簡

化?能否讓類的使用者,只分配對象,而

不用調用delete?

■示例3.23(在示例3.22基礎之上)

線程創建的再封裝

■在有些情況下,新線程的創建者,可能不

需要等待新線程死亡,即不調用

WaitForDeath

■這樣3.23的釋放對象方式將失效???

■示例3.24(在示例3.23基礎之上)

?增加一個標識,讓用戶指定他是否需要等待新

線程死亡

線程創建的再封裝

1

■產生異常的原因在于:111'V

>新線程在主線程調用WaitForDeath之前就已經退出了

>甚至有可能在主線程剛調用完pthread_create之后,

就退出了

■解決辦法:?????????

>需要保證在Run方法退出之前,新線程不會死亡

A若用戶選擇了不等待新線程死亡,則他就不應該再調

fflWaitForDeath

?另外,從語義上講,Run方法返回前,應保證新線程

確實已經被創建了

A示例3.28(在示例3.24基礎之上)

?線程的基本概念

?線程的創建與終止II

?線程創建的封裝111

.線程的同步

g線程創建的再封裝

■Windows消息在Linux的重現

Windows消息在Linux的重現

■在windows中,進行線程之間的通信十分

簡便。Windows系統為每個線程都配備了

二個消息隊列..................

■調用PostThreadMessage函數,可以向一

1個線程發送消息??????

■調用GetMessage函數,可以從消息隊列中

獲取一個消息

生產者/消費者模型

■消息隊列及機制,是一種典型的生產者/消

費者模型應用。

■發送消息的線程(生產者):將消息投入

到消息隊列后,即返回

■消息的接收線程(消費者):一直處于阻

塞等待狀態,直到有線程將消息投入到消

息隊列中

■我們的目標:建立一個自定義的消息隊列

,以實現同一進程內線程之間的通信

Windows消息在Linux的重現

■梏息的封裝111111-

■自定義消息隊列的實現1,11

■消息循環機制的封裝11111

■創建線程與消息循環的結合III

■簡單的名字服務..................

■使用的簡化

Windows消息在Linux的重現

■消息的封裝.....................?

■自定義消息隊列的實現1,11

■消息循環機制的封裝..............

■創建線程與消息循環的結合,11

■簡單的名字服務..................

■使用的簡化

消息的封裝__________

■Windows的線程消息:

BOOLWINAPIPostThreadMessage(

DWORDidThread,

UINTMsg,

WPARAMwParam,

LPARAMIParam

);

■Windows的消息包含了線程ID,以及兩個自定義

參數,不符合面向對象的思想

■需要建立起有關消息的繼承體系

消息的繼承體系

■示例3.29

■CLMessage是對消息的抽象,僅包含了消

息的ID

■線程之間發送的具體消息,需要從??

CLMessage派生,并定義屬于該消息自己

的參數

Windows消息在Linux的重現

■消息的封裝111111-

■自定義消息隊列的實現||||

■消息循環機制的封裝..............

■創建線程與消息循環的結合111

■簡單的名字服務..................

■使用的簡化

自定義消息隊列的實現

■隊列本身采用STL庫中的queue類,該類型

的隊列能自動增長................

■必須以線程安全的方式,將消息放入到隊

列中,然后通知等待的線程消息已到達

■通知的機制可以采用CLEvent類,但3.21

示例中的CLEvent必須改造

■示例3.30

自定義消息隊列的實現

■CLMessageQueue的實現

■示例3.31

■在上例中,采用STL的queue實現了消息隊

歹U]??????????

■也可以采用其他方式實現,例如管道、網

絡通信、自定義的隊列等等

■如何封裝這一變化點?它們之間是否有共

通的部分(均為生產者/消費者模型應用)

Windows消息在Linux的重現

■消息的封裝111111-

■自定義消息隊列的實現||||

溫馨提示

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

評論

0/150

提交評論