Symbian OS:線程編程中文版
雖然symbian操作系統(tǒng)中對(duì)多任務(wù)的實(shí)現(xiàn)更提倡使用活動(dòng)對(duì)象,但多線程也是非常有用的技術(shù),當(dāng)移植程序、后臺(tái)大量復(fù)雜運(yùn)算或多媒體編程時(shí),threads都是必不可少的。symbian中的thread編程和一般的多線程編程差不多,下面就來(lái)看看具體文檔中是如何描述的:
《Symbian OS:線程編程》
Symbian操作系統(tǒng)中的線程和進(jìn)程
在Symbian操作系統(tǒng)中,每個(gè)進(jìn)程都有一個(gè)或多個(gè)線程。線程是執(zhí)行的基本單位。一個(gè)進(jìn)程的主線程是在進(jìn)程啟動(dòng)時(shí)生成的。
Symbian屬于搶占式多任務(wù)操作系統(tǒng),這意味著每個(gè)線程都有自己的執(zhí)行時(shí)間,直到系統(tǒng)將CPU使用權(quán)給予其他線程。當(dāng)系統(tǒng)調(diào)度時(shí),具有最高優(yōu)先權(quán)的線程將首先獲得執(zhí)行。
進(jìn)程邊界是受內(nèi)存保護(hù)的。所有的用戶進(jìn)程都有自己的內(nèi)存地址空間,同一進(jìn)程中的所有線程共享這一空間,用戶進(jìn)程不能直接訪問(wèn)其他進(jìn)程的地址空間。
每個(gè)線程都有它自己的stack和heap,這里heap可以是私有的,也可以被其他線程共享。應(yīng)用程序框架生成并安裝了一個(gè)active scheduler,并且為主線程準(zhǔn)備了清除棧。如果沒(méi)有使用框架(如編寫(xiě)exe程序)那就要手動(dòng)生成這些了:)
Symbian操作系統(tǒng)專為單線程應(yīng)用優(yōu)化,因此強(qiáng)烈推薦使用“活動(dòng)對(duì)象”代替多線程。
[使用單線程的優(yōu)點(diǎn)]
在每個(gè)線程都有自己的stack空間時(shí),使用單線程可以減少內(nèi)存耗費(fèi)。
在線程間切換上下文要比切換活動(dòng)對(duì)象(通過(guò)active scheduler)慢得多。
不需要處理互斥現(xiàn)象,這減少了程序的負(fù)擔(dān),簡(jiǎn)化了代碼,減少了錯(cuò)誤發(fā)生的幾率。
一些資源只能為主線程所用,因此它們并不是線程安全的,如動(dòng)態(tài)數(shù)組。
[使用多線程的優(yōu)點(diǎn)]
有時(shí)為了保證所執(zhí)行的任務(wù)的持續(xù)性,如播放聲音時(shí),我們可以將其歸在一個(gè)單獨(dú)的線程中處理。
將復(fù)雜的多線程或長(zhǎng)時(shí)間運(yùn)行程序移植到Symbian上,如果不使用多線程處理,可能會(huì)比較難也更耗時(shí)間。
(題外話:我曾綺將一個(gè)棋類程序移植到symbian上,里面復(fù)雜的遞歸運(yùn)算使我不得不使用多線程,這樣的情況下,你是很難將時(shí)間有序的分化開(kāi)來(lái),使用活動(dòng)對(duì)象的)
[線程的基本使用方法]
RThread提供了線程的各項(xiàng)功能。線程是為內(nèi)核所擁有的對(duì)象,RThread對(duì)象封裝了這些對(duì)象的句柄。
1、生成一個(gè)新線程
新的線程可以通過(guò)構(gòu)造一個(gè)RThread對(duì)象,并調(diào)用它的Create()函數(shù)生成。如:
Code:
1: TInt threadFunction(TAny *aPtr)
2:
7:
8: RThread thread;
9: thread.Create(KThreadName, threadFunction, 4096,
10: KMinHeapSize, 256*KMinHeapSize, &iParameter);
11: thread.Resume();
2、線程狀態(tài)
一個(gè)線程的最重要的狀態(tài)為運(yùn)行、準(zhǔn)備、等待和暫停。在生成后,線程首先處于暫停狀態(tài),你可以調(diào)用Resume()函數(shù)來(lái)啟動(dòng)它的運(yùn)行。一個(gè)線程也可以通過(guò)調(diào)用Suspend()來(lái)進(jìn)入中斷狀態(tài)。
線程一般通過(guò)Kill(TInt aReason)來(lái)結(jié)束,Terminate()與其相似。如果一個(gè)進(jìn)程的主線程結(jié)束,則該進(jìn)程與所屬所有線程都將結(jié)束。
一種非正常關(guān)閉線程的方式就是調(diào)用Panic(const TDesC& aCategory, TInt aReason)來(lái)中斷執(zhí)行。
如何獲得中斷線程的信息呢,我們可通過(guò)ExitType(),ExitReason()以及ExitCategory()方法來(lái)獲得。
線程可以在中斷時(shí)發(fā)出請(qǐng)求,我們通過(guò)調(diào)用異步方法Logon()來(lái)完成此任務(wù)。返回值在aStatus中。LogonCancel()可以取消前次請(qǐng)求。
void Logon(TRequestStatus& aStatus) const;
TInt LogonCancel(TRequestStatus& aStatus) const;
我們可以通過(guò)SetProtected(ETrue)方法將線程保護(hù)起來(lái),也可以通過(guò)SetProtected(EFalse)來(lái)取消保護(hù)。在保護(hù)時(shí),另一個(gè)線程是無(wú)法中斷、結(jié)束、異常中斷或設(shè)置該線程的優(yōu)先級(jí)的。Protected()方法可以返回該線程的保護(hù)狀態(tài)。
3、訪問(wèn)線程及進(jìn)程
我們可以通過(guò)構(gòu)造一個(gè)RThread對(duì)象來(lái)訪問(wèn)當(dāng)前線程。Id()方法可以返回改線程的ID。
擁有此線程的進(jìn)程可以通過(guò)訪問(wèn)RThread的Process(RProcess& aProcess)方法來(lái)獲得。這里傳入的參數(shù)應(yīng)該是一個(gè)RProcess對(duì)象。
其他線程可以通過(guò)Open()方法來(lái)訪問(wèn)。我們通過(guò)傳遞TThreadId、線程名稱或TFindThread對(duì)象來(lái)打開(kāi)線程。
TInt Open(const TDesC& aFullName, TOwnerType aType=EOwnerProcess);
TInt Open(TThreadId aID, TOwnerType aType=EOwnerProcess);
TInt Open(const TFindThread& aFind, TOwnerType aType=EOwnerProcess);
Code:
1: // * as a wildcard for the name search
2: _LIT(KFindAll, “*”);
3: // default RThread object, has a handle of the current thread
4: RThread thread;
5: TFullName fullName;
6: TFindThread finder(KFindAll);
7:
8: while (finder.Next(fullName) == KErrNone)
9:
(未完待續(xù))
BestRegards
hoolee
hoolee
View Public Profile
Send email to hoolee
Find all posts by hoolee
Add hoolee to Your Buddy List
#2 2005-04-28, 08:20
hoolee
Registered User Join Date: Mar 2005
Posts: 1,037
4、線程優(yōu)先級(jí)
線程可以被賦予一個(gè)絕對(duì)或相對(duì)的優(yōu)先級(jí)。絕對(duì)優(yōu)先級(jí)定義了這個(gè)線程的總體優(yōu)先級(jí),不需要考慮其擁有者進(jìn)程的優(yōu)先級(jí)了。而賦予相對(duì)優(yōu)先級(jí)時(shí)則將此線稱定義為擁有者進(jìn)程的優(yōu)先級(jí)加上該相對(duì)優(yōu)先級(jí)后的結(jié)果。
下面粗體標(biāo)示的優(yōu)先級(jí)值可以由用戶代碼設(shè)置:
Code:
enum TProcessPriority
;
enum TThreadPriority
;
上面枚舉出來(lái)的值中絕對(duì)優(yōu)先級(jí)值為:
EPriorityAbsoluteVeryLow, EPriorityAbsoluteLow, EPriorityAbsoluteBackground, EPriorityAbsoluteForeground, EPriorityAbsoluteHigh.
相對(duì)優(yōu)先級(jí)值為:
EPriorityMuchLess, EPriorityLess, EPriorityNormal, EPriorityMore, EPriorityMuchMore.
EPriorityNull是一個(gè)特殊值,它定義了最低的級(jí)別,Kernel idel thread使用的就是它*_*
EPriorityRealTime定義了除核心服務(wù)線程優(yōu)先級(jí)外最高的總體優(yōu)先級(jí)。
RThread中的Priority()方法返回了一個(gè)線程的優(yōu)先級(jí)(按以上描述值)。我們也可以通過(guò)SetPriority(TThreadPrioriy aPriority)方法來(lái)修改優(yōu)先級(jí)。
ProcessPriority()方法返回了擁有該線程之進(jìn)程的優(yōu)先級(jí)(按TProcessPriority描述值)。我們也可以通過(guò)SetProcessPriority(TProcessPriority)方法來(lái)修改該進(jìn)程的優(yōu)先級(jí)。
5、異常處理
每個(gè)線程都有自己的異常處理模塊。當(dāng)線程發(fā)生異常時(shí)會(huì)調(diào)用異常處理模塊。異常處理模塊的訽型為:
typedef void TExceptionHandler(TExcType);
RThread包含了下列異常處理相關(guān)的方法:
TExceptionHandler* ExceptionHandler()
返回該線程當(dāng)前異常處理模塊的地址。
TInt SetExceptionHandler(TExceptionHandler* aHandler, TUint32 aMask);
定義了該線程新的異常處理模塊的地址,以及它所處理異常的類別。
void ModifyExceptionMask(TUint32 aClearMask, TUint32 aSetMask)
修改異常處理模塊所定之異常類別,aClearMask參數(shù)定義了不再為異常處理模塊所處理的類別,而aSetMask則定義了新的處理類別。
TInt RaiseException(TExcType aType);
引發(fā)線程上指定類型的異常,這時(shí)異常處理模塊將被啟動(dòng)執(zhí)行(發(fā)生在調(diào)用之后)。
TBool IsExceptionHandled(TExcType aType);
檢查線程的異常處理模塊是否捕捉到aType類型的異常。
(1)異常類別及類型
異常類型是一組針對(duì)單個(gè)異常的類型識(shí)別,主要用在異常發(fā)生時(shí)。
異常類別則代表一組異常形式。
異常類別的一個(gè)集是由一個(gè)或多個(gè)異常類別通過(guò)OR形式組合成的,如KExceptionInteger|KExceptionDebug,這些值用來(lái)設(shè)置及修改異常處理模塊所處理的類別。
下面列示了所有的類型及類別。
異常類別 異常類型
KExceptionInterrupt ->EExcGeneral, EExcUserInterrupt
KExceptionInteger ->EExcIntegerDivideByZero, EExcIntegerOverflow
KExceptionDebug->EExcSingleStep, EExcBreakPoint
KExceptionFault ->EExcBoundsCheck, EExcInvalidOpCode, EExcDoubleFault, EExcStackFault, EExcAccessViolation, EExcPrivInstruction, EExcAlignment, EExcPageFault
KExceptionFpe ->EExcFloatDenormal, EExcFloatDivideByZero, EExcFloatIndexactResult, EExcFloatInvalidOperation, EExcFloatOverflow, EExcFloatStackCheck, EExcFloatUnderflow
KExceptionAbort ->EExcAbort
KExceptionKill->EExcKill
(未完等續(xù))
BestRegards
hoolee
hoolee
View Public Profile
Send email to hoolee
Find all posts by hoolee
Add hoolee to Your Buddy List
#3 2005-04-28, 09:56
zaohuzi888
Member Join Date: Mar 2005
Posts: 5
精彩啊
--------------------------------------------------------------------------------
不知道后面的什么時(shí)候推出,很期待哦
zaohuzi888
View Public Profile
Send email to zaohuzi888
Find all posts by zaohuzi888
Add zaohuzi888 to Your Buddy List
#4 2005-04-29, 09:36
hoolee
Registered User Join Date: Mar 2005
Posts: 1,037
6、其他線程函數(shù)
TInt Rename(const TDesC& aName)
為線程定義個(gè)新名字。
void RequestComplete(TRequestStatus*& aStatus, TInt aReason)
通知線程與一個(gè)異步請(qǐng)求綁定的請(qǐng)求狀態(tài)對(duì)象aStatus已綺完成。sStatus完成代碼將負(fù)責(zé)設(shè)置aReason及發(fā)出線程請(qǐng)求信號(hào)的通知。
TInt RequestCount()
返回線程請(qǐng)求信號(hào)的數(shù)目。如果是負(fù)值則表示該線程正在等待至少一個(gè)異常請(qǐng)求的完成。
void HandleCount(TInt& aProcessHandleCount, TInt& aThreadHandleCount)
得到線程中及擁有該線程的進(jìn)程中處理模塊的數(shù)目。
RHeap* Heap()
返回一個(gè)指向改線程堆的指針。
TInt GetRamSizes(TInt& aHeapSize, TInt& aStackSize)
得到該線程中堆和棧的大小。
TInt GetCpuTime(TTimeIntervalMicroSeconds& aCpuTime)
得到改線程所分配到的CPU時(shí)間
void Context(TDes8& aDes)
得到該線程( sleeping狀態(tài))所注冊(cè)的上下文環(huán)境。
4、線程內(nèi)部的通信
1)共享內(nèi)存
在線程間交換信息最直接的方法就是使用共享內(nèi)存。線程入口函數(shù)中有一個(gè)參數(shù)TAny* aPtr,這個(gè)指針可以用于任何目的。通常可以用它來(lái)傳遞一個(gè)負(fù)責(zé)線程間共享信息的數(shù)據(jù)結(jié)構(gòu)或類實(shí)例。因?yàn)橥贿M(jìn)程中的線程是共享內(nèi)存地址空間的,因此這里指針?biāo)赶虻臄?shù)據(jù)可以被兩個(gè)線程所共享,注意訪問(wèn)該數(shù)據(jù)時(shí)必須是同步形式。
另外這里的指針參數(shù)可以使用SetInitialParameter(TAny* aPtr)方法來(lái)改變,但這時(shí)線程應(yīng)處于suspend狀態(tài)。
2)Client/Server API
Symbian操作系統(tǒng)提供了一組基于server/session的API,允許一個(gè)線程扮演server的角色,向其他線程或進(jìn)程提供服務(wù)。這里API也提供處理一組方法處理信息的傳遞,異步以數(shù)據(jù)傳輸。
3)進(jìn)程內(nèi)數(shù)據(jù)傳輸
如果兩個(gè)線程分屬不同的進(jìn)程,則他們無(wú)法直接管理需要通信的數(shù)據(jù),因?yàn)樗麄儧](méi)有共享的數(shù)據(jù)區(qū)。這里可以使用RThread提供的ReadL()方法及WriteL()方法,我們可以用來(lái)在當(dāng)前線程和由RThread提供的另一個(gè)線程間的地址空間拷貝8/16位的數(shù)據(jù)。這里當(dāng)前線程和另一個(gè)線程可以歸屬同一個(gè)進(jìn)程也可分屬不同進(jìn)程。
數(shù)據(jù)的傳輸是通過(guò)拷貝數(shù)據(jù)來(lái)完成的,RThread提供了方法返回在它地址空間內(nèi)一個(gè)descriptor的長(zhǎng)度及最大允許長(zhǎng)度。
a>讀取另個(gè)線程所提供的descriptor
void ReadL(const TAny* aPtr,TDes8& aDes,TInt anOffset) const;
void ReadL(const TAny* aPtr,TDes16 &aDes,TInt anOffset) const;
這里ReadL()方法從另一個(gè)線程的descriptor(由aPtr所指)中拷貝一組數(shù)據(jù),傳遞到當(dāng)前線程的descriptor(由aDes所指)。
aPtr指針必須指向一個(gè)在RThread句柄所指線程的地址空間中有效的descriptor。
從源descriptor中的內(nèi)容是從anOffset位置那里開(kāi)始拷貝到目的descriptor(aDes)的。
b)向另個(gè)線程寫(xiě)入descriptor
void WriteL(const TAny* aPtr, const TDesC8& aDes, TInt anOffset) const;
void WriteL(const TAny* aPtr, const TDesC16& aDes, TInt anOffset) const;
用這個(gè)方法將當(dāng)前線程descritor(aDes)所提供的數(shù)據(jù)都拷貝在另一個(gè)線程(aPtr所指)的descriptor中。這里anOffset參數(shù)設(shè)定了目標(biāo)descriptor的初始化拷貝位置。
aPtr為線程地址空間內(nèi)有效的可修改descriptor。
如果拷貝進(jìn)去的數(shù)據(jù)長(zhǎng)度超過(guò)目標(biāo)descriptor的最大長(zhǎng)度,則函數(shù)會(huì)發(fā)生異常。
c)Descriptor幫助函數(shù)
TInt GetDesLength(const TAny* aPtr) const;
TInt GetDesMaxLength(const TAny* aPtr) const;
這里RThread的GetDesLength()方法可以返回aPtr所指向的descriptor長(zhǎng)度。這里descriptor必須為RThread句柄所指定的線程的地址空間中。
RThread的GetMaxDesLength()方法返回aPtr所指向descriptor的最大長(zhǎng)度。descriptor也應(yīng)在RThread句柄所指的線程地址空間中。
建議在ReadL()和WriteL()等方法前使用這些函數(shù)。
4.4線程局部存儲(chǔ)(TLS)
Symbian操作系統(tǒng)是不允許在DLL中出現(xiàn)可寫(xiě)靜態(tài)變量的。然而每個(gè)DLL中每個(gè)線程都會(huì)分配一個(gè)32位字符空間。這個(gè)字符用來(lái)存放一個(gè)指向數(shù)據(jù)結(jié)構(gòu)或類示例的指針。分配和釋放這些資源可在例如DLL的入口函數(shù)E32Dll中處理。
另一個(gè)使用線程局部存儲(chǔ)的示例為保存指向類示例的指針,這樣靜態(tài)回調(diào)函數(shù)可以訪問(wèn)與線程相聯(lián)系的該對(duì)象。當(dāng)我們處理自定義異常處理模塊時(shí)是很有用的。
Dll::SetTls(TAny *aPtr)函數(shù)負(fù)責(zé)設(shè)置線程局部存儲(chǔ)的指針。
Dll::Tls()函數(shù)負(fù)責(zé)返回一個(gè)指向線程局部存儲(chǔ)的指針。取得后該指針?biāo)付〝?shù)據(jù)可以正常使用。
4.5 User-Interrupt Exception
如3.5“Exception Handling”所述,線程可以引發(fā)其他線程的異常。有一種異常類型是專為用戶所保留的,那就是EExcUserInterrupt,可以通過(guò)指定異常類型KExceptionUserInterrupt來(lái)處理。其他要傳遞的信息應(yīng)該通過(guò)共享內(nèi)存來(lái)處理。這是在最段時(shí)間內(nèi)向其他線程傳遞信息的方式,當(dāng)異常發(fā)生時(shí)調(diào)用RaiseException()函數(shù)可切換到另個(gè)線程的異常處理模塊。
(未完待續(xù))
BestRegards
hoolee
hoolee
View Public Profile
Send email to hoolee
Find all posts by hoolee
Add hoolee to Your Buddy List
#5 2005-04-30, 07:54
hoolee
Registered User Join Date: Mar 2005
Posts: 1,037
4.6 Publish & Subsribe
Publish & Subscrible是一個(gè)進(jìn)程間的通信機(jī)制(在SymbianOS v8.0a和Series 60 Platform 2nd Editon, Feature Pack2中有所介紹),可以查看相關(guān)的文擋。
這個(gè)機(jī)制包括了三個(gè)基本方面:properties, publishers, 和subscribers.Properties是由一個(gè)標(biāo)準(zhǔn)SymbianOS UID所定義的全局唯一變量,它定義了屬性類別,而另一個(gè)整數(shù)定義了property sub-key。
Publishers是負(fù)責(zé)更新屬性的線程。Subscribers是負(fù)責(zé)監(jiān)聽(tīng)屬性變化的線程。
4.7 消息隊(duì)列
消息隊(duì)列是另一個(gè)進(jìn)程間通信的機(jī)制(在SymbianOS v8.0a和Series 60 Platform 2nd Editon, Feature Pack2中有所介紹)。
消息隊(duì)列用來(lái)向隊(duì)列發(fā)送消息,而無(wú)需獲得接收者的狀態(tài)標(biāo)識(shí)信息。任何進(jìn)程(都在同一隊(duì)列中的)或任何同一進(jìn)程中的線程(在局部隊(duì)列中)都可以讀取這些信息。
5、同步
1)目的
如果多個(gè)線程在沒(méi)有保護(hù)機(jī)制的情況下使用同一資源,就會(huì)出現(xiàn)一些問(wèn)題。如,線程A更新了部分descriptor,而線程B接手后又重寫(xiě)了內(nèi)容。回到線程A后,又開(kāi)始更新內(nèi)容。這樣descriptor的內(nèi)容就在A與B中來(lái)回修改了。
為了防止這類情況的發(fā)生,你需要使用非搶占式client/server機(jī)制或同步對(duì)象來(lái)處理。同步對(duì)象(mutex, semaphore, critical section)都是核心對(duì)象,可以通過(guò)句柄來(lái)訪問(wèn)。他們會(huì)限制或直接鎖住對(duì)多線程們所要訪問(wèn)的資源,這種資源形式被稱為共享資源。
在任何時(shí)刻只能有一個(gè)線程對(duì)共享資源進(jìn)行寫(xiě)操作,每個(gè)要訪問(wèn)資源的線程都應(yīng)使用同步機(jī)制來(lái)管理資源。
同步操作一般有如下步驟:
1. Call Wait() of the synchronization object reserved for this resource.
2. Access the shared resource.
3. Call Signal() of the synchronization object reserved for this resource.
注意,當(dāng)kill線程時(shí)要小心點(diǎn)。因?yàn)槿绻€程使用已綺注銷的對(duì)象,不同的同步對(duì)象其處理方式是不同的。因此,忽略使用同步類型而kill一個(gè)已綺更新過(guò)部分資源的線程是會(huì)引發(fā)問(wèn)題的。
2)使用Semaphores(信號(hào))
Semaphores可以管理共享資源的同步化訪問(wèn)。這里semaphore的句柄可通過(guò)RSemaphore類獲得。
Semaphore限制了同一時(shí)刻訪問(wèn)共享資源的數(shù)目。semaphore計(jì)數(shù)的初始化工作可以放在構(gòu)造函數(shù)中進(jìn)行。
Semaphore可以是全局的也可以是局部的,全局的semaphore有自己的名稱,可以被其他進(jìn)程搜索并使用。而局部的semaphore沒(méi)有名稱,只能在同一進(jìn)程間的線程中使用。
調(diào)用semaphore的Wait()方法將減少semaphore計(jì)數(shù),而如果計(jì)數(shù)為負(fù)的話,調(diào)用線程就會(huì)進(jìn)入等待狀態(tài)。
調(diào)用semaphore的Signal()方法將增加semaphore計(jì)數(shù),如果增長(zhǎng)之前為負(fù)數(shù),則等待信號(hào)的第一個(gè)線程將設(shè)定為準(zhǔn)備運(yùn)行狀態(tài)。
調(diào)用semaphore的Signal(TInt aCount)和調(diào)用n次Signal()效果是一樣的。
當(dāng)線程死亡時(shí),只有該線程正等待該信號(hào)時(shí),信號(hào)才能被通知。因?yàn)樾盘?hào)在下面這樣的情況也是可以執(zhí)行的:在一個(gè)線程中調(diào)用Wait(),在另一個(gè)線程中調(diào)用Signal(),這樣的信號(hào)無(wú)法在使用它的線程死亡時(shí)被通知。這樣只會(huì)導(dǎo)致信號(hào)計(jì)數(shù)減低。
3)使用互斥(Mutex)
互斥主要使用在同步下獨(dú)占訪問(wèn)共享資源。它的句柄可以通過(guò)RMutex類來(lái)獲得。
和信號(hào)一樣,互斥可以是全局也可以是局部的。唯一的不同在于其計(jì)數(shù)初始化時(shí)總為1。Mutex因此只允許最多一個(gè)訪問(wèn)共享資源。
如果一個(gè)線程已綺為mutex調(diào)用Wait(),但沒(méi)有Signal(),則線程死亡時(shí)該互斥將被通知。
4)使用臨界區(qū)(Critical Sections)
Critical Sections可用來(lái)在一單獨(dú)進(jìn)程中獨(dú)占訪問(wèn)共享資源。Critical Sections句柄可以通過(guò)RCriticalSection類來(lái)獲得。
Critical Sections只能用在同一進(jìn)程的線程間,通常它用來(lái)管理某段代碼的訪問(wèn),每次只能有一個(gè)線程來(lái)訪問(wèn)。
同一線程中,在調(diào)用Wait()前調(diào)用Signale()將會(huì)引發(fā)線程的異常。但不會(huì)出現(xiàn)在其他類型的同步對(duì)象中。
線程的中斷是不會(huì)影響critical sections的狀態(tài)的,因此使用critical sections的線程將不會(huì)被其他線程殺死,除非不在critical sections中。當(dāng)不在需要時(shí),線程的死亡是不會(huì)有癬,很安全的。
5)同步實(shí)例
Code:
1: class CMessageBuffer
2: ;
12:
13: CMessageBuffer::CMessageBuffer()
14:
17:
18: void CMessageBuffer::AddMessage(const TDes &aMsg)
19:
24:
25: void CMessageBuffer::GetMessages(TDes &aMsgs)
26:
32:
33: static void CMyClass::threadFunction(TAny *aPtr)
34:
45: }
在上面所述中,CMessageBuffer是一個(gè)半成品類,它允許用戶增加消息到buffer中,也允許獲得所有消息。
線程函數(shù)CMyClass::threadFunction負(fù)責(zé)向CMessageBuffer共享對(duì)象添加信息,這里內(nèi)存分配和錯(cuò)誤檢查并沒(méi)有列出,需要讀者自己完成。
假設(shè)有多個(gè)線程要共享CMessageBuffer對(duì)象實(shí)例,則在實(shí)際訪問(wèn)buffer時(shí)必須要同步來(lái)處理。我們也可在線程函數(shù)中完成,但在CMessageBuffer中完成同步將使得該類成為線程安全級(jí),同樣它也可以被用在單個(gè)線程中了。
6總結(jié)
很多情況下都需要多線程的,當(dāng)使用多線程時(shí),同步及互斥排他也要考慮在內(nèi),以便保證線程通信的安全性。如果線程使用共享資源,我們應(yīng)該使用某種同步機(jī)制來(lái)避免異常的發(fā)生,Semaphores, critical sections,和mutexes都提供了基本的解決方案。此外,如果使用活動(dòng)對(duì)象或清除機(jī)制,我們還需要手工設(shè)置active scheduler和清除棧。總的來(lái)說(shuō),線程編程不是這么容易的,因?yàn)檫@類編程需要全面理解框架、多任務(wù)和線程安全機(jī)制。
| 只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。 | ||
|
||
網(wǎng)站導(dǎo)航:
博客園
IT新聞
BlogJava
博問(wèn)
Chat2DB
管理
|
||
|
|