C++ Builder 高手進階 (五)用BCB編寫多執行緒應用程式 (轉)

worldblog發表於2008-06-17
C++ Builder 高手進階 (五)用BCB編寫多執行緒應用程式 (轉)[@more@] 

C++ Builder 高手進階

(五)用BCB編寫多執行緒應用

to:nxyc_twz@163.com">nxyc_twz@163.com

 
  隨著的全球性普及,多執行緒技術已越來越多地運用到許多設計中。使用多執行緒技術可全面提高應用程式的。以前為了實現多執行緒,基本上都是一系列的,如CreateThread、ResumeThread等,不容易控制,還容易出錯。在使用BCB以後,我才發現原來編寫多執行緒程式也可以如此簡單!BCB為我們提供了強大的TThread類,從而使得多執行緒程式設計變得非常簡便易用。下面請跟我一起開始我們的BCB多執行緒程式設計之旅。
  1. 建立多執行緒程式:
  首先,我介紹一下BCB中編寫多執行緒程式的具體步驟。
  在C++Builder 環境下選擇選單File|New,在New欄中選中Thread ,按OK,接下來彈出輸入框,輸入TThread子類的名字NewThread,這樣C++Builder自動為你建立了一個名為TNewThread的TThread子類。下面是TNewThread的部分原始碼:
 __fastcall NewThread::MyThread(bool CreateSuspended)
   : TThread(CreateSuspended)
  {//建構函式,可用來初始化一些資訊
  }
  void __fastcall NewThread::Execute()
  {
   //多執行緒程式的核心,用來執行相關多執行緒操作
  }

  BCB中的Execute()函式是我們要線上程中實現的任務程式碼所在地。使用多執行緒時,動態建立一個TNewThread 物件,在建構函式中使用Resume()方法,具體執行的程式碼使用Execute()方法過載的程式碼。如果想建立更多的執行緒,只需要建立需要數量的TNewThread 而已。
  透過以上步驟我們基本實現了在程式中如何建立一個執行緒,並使程式實現了多執行緒應用。但是,多執行緒應用的實現,並不是一件簡單的工作,還需要考慮很多使多個執行緒能在系統中共存、互不影響的因素。比如,程式中公共變數的訪問、資源的分配,如果處理不當,不僅執行緒會死鎖陷入混亂,甚至可能會造成系統崩潰。總的來講,在多執行緒程式設計中要注意共享物件和資料的處理,不能忽視。因此,下面我們要講的就是多執行緒中常見問題:
  2. 多執行緒中VCL物件的使用
  我們都知道,C++Builder程式設計是建立在VCL類庫的基礎上的。在程式中經常需要訪問VCL物件的屬性和方法。不幸的是,VCL類庫並不保證其中物件的屬性和方法是執行緒訪問的(Thread_safe),訪問VCL物件的屬性或呼叫其方法可能會訪問到不被別的執行緒所保護的區域而產生錯誤。因此,TThread物件提供了一個Synchronize方法,當需要線上程中訪問VCL物件屬性或呼叫方法時,透過Synchronize方法來訪問屬性或呼叫方法就能避免衝突,使各個執行緒之間協調而不會產生意外的錯誤。如下所示:
  void __fastcall TNewThread::PushTheButton(void)
  
  {
   Button1->Click();
  }
  
  void __fastcall TNewThread::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 TNewThread : public TThread
  {
   ...
  private:
  TCriticalSection pLockX;
  int x;
  float y;
  ...
  };
  void __fastcall TNewThread::Execute()
  {
  ...
  pLockX->Acquire();
  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()等等。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-1005748/,如需轉載,請註明出處,否則將追究法律責任。

相關文章