2. 多線程中VCL對(duì)象的使用
我們都知道,C++Builder編程是建立在VCL類庫(kù)的基礎(chǔ)上的。在程序中經(jīng)常需要訪問(wèn)VCL對(duì)象的屬性和方法。不幸的是,VCL類庫(kù)并不保證其中對(duì)象的屬性和方法是線程訪問(wèn)安全的(Thread_safe),訪問(wèn)VCL對(duì)象的屬性或調(diào)用其方法可能會(huì)訪問(wèn)到不被別的線程所保護(hù)的內(nèi)存區(qū)域而產(chǎn)生錯(cuò)誤。因此,TThread對(duì)象提供了一個(gè)Synchronize方法,當(dāng)需要在線程中訪問(wèn)VCL對(duì)象屬性或調(diào)用方法時(shí),通過(guò)Synchronize方法來(lái)訪問(wèn)屬性或調(diào)用方法就能避免沖突,使各個(gè)線程之間協(xié)調(diào)而不會(huì)產(chǎn)生意外的錯(cuò)誤。如下所示:
void __fastcall TMyThread::PushTheButton(void)
{
Button1->Click();
}
void __fastcall TMyThread::Execute()
{
...
Synchronize((TThreadMethod)PushTheButton);
...
}
對(duì)Button1-〉Click()方法的調(diào)用就是通過(guò)Synchronize()方法來(lái)實(shí)現(xiàn)的,它可以自動(dòng)避免發(fā)生多線程訪問(wèn)沖突。在C++Builder中,雖然有一些VCL對(duì)象也是線程訪問(wèn)安全的(如TFont、TPen、TBrush等),可以不用Sychronize()方法對(duì)它們的屬性方法進(jìn)行訪問(wèn)調(diào)用以提高程序性能,但是,對(duì)于更多的無(wú)法確定的VCL對(duì)象,還是強(qiáng)烈建議使用Synchronize()方法確保程序的可靠性。
3. 多線程中公共數(shù)據(jù)的使用
程序設(shè)計(jì)中難免要在多個(gè)線程中共享數(shù)據(jù)或者對(duì)象。為了避免在多線程中因?yàn)橥瑫r(shí)訪問(wèn)了公共數(shù)據(jù)塊而造成災(zāi)難性的后果,我們需要對(duì)公共數(shù)據(jù)塊進(jìn)行保護(hù),直到一個(gè)線程對(duì)它的訪問(wèn)結(jié)束為止。這可以通過(guò)臨界區(qū)域(Critical Section)的使用來(lái)實(shí)現(xiàn),所幸的是在C++Builder中,給我們提供了一個(gè)TCriticalSection對(duì)象來(lái)進(jìn)行臨界區(qū)域的劃定。該對(duì)象有兩個(gè)方法,Acquire()和Release()。它設(shè)定的臨界區(qū)域可以保證一次只有一個(gè)線程對(duì)該區(qū)域進(jìn)行訪問(wèn)。如下例所示:
class MyThread : public TThread
{
...
private:
TCriticalSection pLockX;
int x;
float y;
...
};
void __fastcall MyThread::Execute()
{
...
pLockX->Acquire();//Here pLockX is a Global CriticalSection variable.
x++;
y=sin(x);
pLockX->Release();
...
}
這樣,對(duì)公共變量x,y的訪問(wèn)就通過(guò)全局TCriticalSection 對(duì)象保護(hù)起來(lái),避免了多個(gè)線程同時(shí)訪問(wèn)的沖突。
4. 多線程間的同步
當(dāng)程序中多個(gè)線程同時(shí)運(yùn)行,難免要遇到使用同一系統(tǒng)資源,或者一個(gè)線程的運(yùn)行要依賴另一個(gè)線程的完成等等,這樣需要在線程間進(jìn)行同步的問(wèn)題。由于線程同時(shí)運(yùn)行,無(wú)法從程序本身來(lái)決定運(yùn)行的先后快慢,使得線程的同步看起來(lái)很難實(shí)現(xiàn)。所幸的是Windows系統(tǒng)是多任務(wù)操作系統(tǒng),系統(tǒng)內(nèi)核為我們提供了事件(Event)、Mutex、信號(hào)燈(semaphore)和計(jì)時(shí)器4種對(duì)象來(lái)控制線程間的同步。在C++Builder中,為我們提供了用于創(chuàng)建Event的TEvent 對(duì)象供我們使用。
當(dāng)程序中一個(gè)線程的運(yùn)行要等待一項(xiàng)特定的操作的完成而不是等待一個(gè)特定的線程完成時(shí),我們就可以很方便地用TEvent對(duì)象來(lái)實(shí)現(xiàn)這個(gè)目標(biāo)。首先創(chuàng)建一個(gè)全局的TEvent對(duì)象作為所有線程可監(jiān)測(cè)的標(biāo)志。當(dāng)一個(gè)線程完成某項(xiàng)特定的操作時(shí),調(diào)用TEvent對(duì)象的SetEvent()方法,這樣將設(shè)置這個(gè)標(biāo)志,其他的線程可以通過(guò)監(jiān)測(cè)這個(gè)標(biāo)志獲知操作的完成。相反,要取消這個(gè)標(biāo)志,可以調(diào)用ResetEvent()方法。在需要等待操作完成的線程中使用WaitFor()方法,將一直等待這個(gè)標(biāo)志被設(shè)置為止。注意WaitFor()方法的參數(shù)是等待標(biāo)志設(shè)置的時(shí)間,一般用INFINITE表示無(wú)限等待事件的發(fā)生,如果其它線程運(yùn)行有誤,很容易使這個(gè)線程死?。ǖ却粋€(gè)永不發(fā)生的事件)。
其實(shí)直接用Windows API函數(shù)也可以很方便地實(shí)現(xiàn)事件(Event)、信號(hào)燈(semaphore)控制技術(shù)。尤其是C++Builder,在調(diào)用Windows API方面有著其它語(yǔ)言無(wú)可比擬的優(yōu)勢(shì)。所用的函數(shù)主要有:CreateSemaphore()、CreateEvent()、WaitForSingleObject()、ReleaseSemaphore()、SetEvent()等等,這里就不贅述了。
本文結(jié)合Inprise(Borland)公司開(kāi)發(fā)的強(qiáng)大的RAD工具C++Builder的編程,對(duì)Windows下的多線程編程作了比較全面的介紹。其實(shí)多線程的實(shí)現(xiàn)并不神秘,看了本文,你也可以編出自己的多線程程序,真正體會(huì)多任務(wù)操作系統(tǒng)的威力。
附:本文是本人在使用C++Builder一年來(lái)的一些實(shí)踐體會(huì)。在完成自己的項(xiàng)目的同時(shí),發(fā)現(xiàn)對(duì)多線程的編程一般的書籍都介紹得比較少,而實(shí)際應(yīng)用中,多線程編程又是如此的重要,因此,本文通過(guò)對(duì)多線程編程比較全面的介紹,愿能達(dá)到拋磚引玉之效。