單線程和多線程 |
|
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
http://www.encrypter.net/article_tw/bcb0018.htm 單線程就是進程只有一個線程 多線程就是進程有多個線程 !!!! 下面是多線程的例子 還在Dos時代,人們就在尋求一種多任務的實現。於是出現了TSR類型的後台駐留程式,比較有代表性的有Side Kick、Vsafe等優秀的TSR程式,這類程式的出現和應用確實給用戶使用計算機帶來了極大的方便,比如Side Kick,我們編程可以在不用進編輯程式的狀態下,一邊編輯根源程式,一邊編譯運行,非常方便。但是,Dos單任務操作系統的致命缺陷註定了在Dos下不可能開發出真正的多任務程式。進入Windows3.1時代,這種情況依然沒有根本的改變,一次應用只能做一件事。比如數據庫查詢,除非應用編得很好,在查詢期間整個系統將不響應用戶的輸入。 進入了Windows NT和Windows 9x時代,情況就有了徹底的改觀,操作系統從真正意義上實現了多任務(嚴格地說,Win9x還算不上)。一個應用程式,在需要的時候可以有許多個執行線程,每個線程就是一個小的執行程式,操作系統自動使各個線程共用CPU資源,確保任一線程都不能使系統死鎖。這樣,在編程的時候,可以把費時間的任務移到後台,在前臺用另一個線程接受用戶的輸入。對那些對實時性要求比較高的編程任務,如網絡客戶服務、串列通信等應用時,多線程的實現無疑大大地增強了程式的可用性和穩固性。 在Windows NT和Windows 9x中,多線程的編程實現需要調用一系列的API函數,如CreateThread、ResumeThread等,比較麻煩而且容易出錯。我們使用Inprise公司的新一代RAD開發工具C++Builder,可以方便地實現多線程的編程。與老牌RAD工具Visual Basic和Delphi比,C++Builer不僅功能非常強大,而且它的編程語言是C++,對於系統開發語言是C的Windows系列操作系統,它具有其他編程語言無可比擬的優勢。利用C++Builder提供的TThread對象,多線程的編程變得非常簡便易用。那麼,如何實現呢?且待我慢慢道來,讓你體會一下多線程的強大功能。 1. 創建多線程程式: 首先,先介紹一下實現多線程的具體步驟。在C++Builder中雖然用Tthread對像說明瞭線程的概念,但是Tthread對像本身並不完整,需要在TThread下新建其子類,並重載Execute方法來使用線程對象。在C++Builder下可以很方便地實現這一點。 在C++Builder IDE環境下選擇菜單File|New,在New欄中選中Thread Object,按OK,接下來彈出輸入框,輸入TThread對像子類的名字MyThread,這樣C++Builder自動為你創建了一個名為TMyThread的TThread子類。同時編輯器中多了一個名為Unit2.cpp的單元,這就是我們創建的TMyThread子類的原碼,如下: #include #pragma hdrstop #include 「Unit2.h」 #pragma package(smart_init) //────────────────────- // Important: Methods and properties of objects in VCL can only be // used in a method called using Synchronize, for example: // // Synchronize(UpdateCaption); // // where UpdateCaption could look like: // // void __fastcall MyThread::UpdateCaption() // { // Form1->Caption = 「Updated in a thread」; // } //──────────────────── __fastcall MyThread::MyThread(bool CreateSuspended) : TThread(CreateSuspended) { } //──────────────────── void __fastcall MyThread::Execute() { //──── Place thread code here ──── } //────────────────────- 其中的Execute()函數就是我們要在線程中實現的任務的代碼所在處。在原代碼中包含Unit2.cpp,這個由我們創建的TMyThread對象就可以使用了。使用時,動態創建一個TMyThread 對象,在構造函數中使用Resume()方法,那麼程式中就增加了一個新的我們自己定義的線程TMyThread,具體執行的代碼就是Execute()方法重載的代碼。要加載更多的線程,沒關係,只要繼續創建需要數量的TMyThread 對象就成。 以上我們初步地實現了在程式中創建一個自定義的線程,並使程式實現了多線程應用。但是,多線程應用的實現,並不是一件簡單的工作,還需要考慮很多使多個線程能在系統中共存、互不影響的因素。比如,程式中公共變量的訪問、資源的分配,如果處理不當,不僅線程會死鎖陷入混亂,甚至可能會造成系統崩潰。總的來講,在多線程編程中要注意共用對像和數據的處理,不能忽視。因此,下面我們要講的就是多線程中常見問題: 2. 多線程中VCL對象的使用 我們都知道,C++Builder編程是建立在VCL類庫的基礎上的。在程式中經常需要訪問VCL對象的屬性和方法。不幸的是,VCL類庫並不保證其中對象的屬性和方法是線程訪問安全的(Thread_safe),訪問VCL對象的屬性或調用其方法可能會訪問到不被別的線程所保護的內存區域而產生錯誤。因此,TThread對像提供了一個Synchronize方法,當需要在線程中訪問VCL對像屬性或調用方法時,通過Synchronize方法來訪問屬性或調用方法就能避免衝突,使各個線程之間協調而不會產生意外的錯誤。如下所示: void __fastcall TMyThread::PushTheButton(void) { Button1->Click(); } void __fastcall TMyThread::Execute() { ... Synchronize((TThreadMethod)PushTheButton); ... } 對Button1-〉Click()方法的調用就是通過Synchronize()方法來實現的,它可以自動避免發生多線程訪問衝突。在C++Builder中,雖然有一些VCL對象也是線程訪問安全的(如TFont、TPen、TBrush等),可以不用Sychronize()方法對它們的屬性方法進行訪問調用以提高程式性能,但是,對於更多的無法確定的VCL對象,還是強烈建議使用Synchronize()方法確保程式的可靠性。 3. 多線程中公共數據的使用 程式設計中難免要在多個線程中共用數據或者對象。為了避免在多線程中因為同時訪問了公共數據塊而造成災難性的後果,我們需要對公共數據塊進行保護,直到一個線程對它的訪問結束為止。這可以通過臨界區域(Critical Section)的使用來實現,所幸的是在C++Builder中,給我們提供了一個TCriticalSection對像來進行臨界區域的劃定。該對像有兩個方法,Acquire()和Release()。它設定的臨界區域可以保證一次只有一個線程對該區域進行訪問。如下例所示: 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(); ... } 這樣,對公共變量x,y的訪問就通過全局TCriticalSection 對像保護起來,避免了多個線程同時訪問的衝突。 4. 多線程間的同步 當程式中多個線程同時運行,難免要遇到使用同一系統資源,或者一個線程的運行要依賴另一個線程的完成等等,這樣需要在線程間進行同步的問題。由於線程同時運行,無法從程式本身來決定運行的先後快慢,使得線程的同步看起來很難實現。所幸的是Windows系統是多任務操作系統,系統內核為我們提供了事件(Event)、Mutex、信號燈(semaphore)和計時器4種對像來控制線程間的同步。在C++Builder中,為我們提供了用於創建Event的TEvent 對像供我們使用。 當程式中一個線程的運行要等待一項特定的操作的完成而不是等待一個特定的線程完成時,我們就可以很方便地用TEvent對像來實現這個目標。首先創建一個全局的TEvent對像作為所有線程可監測的標誌。當一個線程完成某項特定的操作時,調用TEvent對象的SetEvent()方法,這樣將設置這個標誌,其他的線程可以通過監測這個標誌獲知操作的完成。相反,要取消這個標誌,可以調用ResetEvent()方法。在需要等待操作完成的線程中使用WaitFor()方法,將一直等待這個標誌被設置為止。注意WaitFor()方法的參數是等待標誌設置的時間,一般用INFINITE表示無限等待事件的發生,如果其他線程運行有誤,很容易使這個線程死住(等待一個永不發生的事件)。 其實直接用Windows API函數也可以很方便地實現事件(Event)、信號燈(semaphore)控制技術。尤其是C++Builder,在調用Windows API方面有著其他語言無可比擬的優勢。所用的函數主要有:CreateSemaphore()、CreateEvent()、WaitForSingleObject()、ReleaseSemaphore()、SetEvent()等等,這裡就不贅述了。 本文結合Inprise(Borland)公司開發的強大的RAD工具C++Builder的編程,對Windows下的多線程編程作了比較全面的介紹。其實多線程的實現並不神秘,看了本文,你也可以編出自己的多線程程式,真正體會多任務操作系統的威力。 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |