在BCB中使用多執行緒例項
一、初識TThread物件
VCL提供了用於多執行緒程式設計的TThread類,在這個類中封裝了Windows關於執行緒機制的Windows API,通常將它的例項成為執行緒物件。執行緒物件通過封裝簡化了多執行緒應用程式的編寫。注意,執行緒物件不允許控制執行緒堆疊的大小或安全屬性。若需要控制這 些,必須使用Windows API的CreateThread()或BeginThread()函式。不過,即使是使用Windows Thread API函式建立和控制多執行緒,仍然可從一些同步執行緒物件或下節將要描述的方法中受益。
要在應用程式中使用執行緒物件,必須建立TThread的一個派生類。File|New|Thread Object,系統會提示為新執行緒物件提供類名,我們將其命名為TMyThread。我們必須自行在建構函式以及Execute()函式中新增程式碼。自動 生成的建構函式中有一個引數,如果為true的話執行緒建立後將進入掛起狀態,直到執行緒物件的Resume()函式被呼叫才開始執行。如果為false則線 程建立後會立刻開始執行。
我們先建立一個例項來親自感受下多執行緒:在窗體上放兩個Button和兩個Edit元件,自動命名。然後File|New|Thread Object來建立一個執行緒物件,命名為TMyThread。
以下請看完整工程程式碼:
//Unit1.h //主窗體標頭檔案
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "Unit2.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TButton *Button2;
TEdit *Edit1;
TEdit *Edit2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
private: // User declarations
TMyThread *thread1,*thread2;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
//Unit1.cpp //主窗體實現檔案
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
thread1->Resume(); //單擊後才啟動執行緒
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
thread2->Resume();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
thread1=new TMyThread(true,Edit1); //建立執行緒物件例項
thread2=new TMyThread(true,Edit2);
}
//---------------------------------------------------------------------------
//Unit2.h //執行緒類標頭檔案
//---------------------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include <Classes.hpp>
//---------------------------------------------------------------------------
class TMyThread : public TThread
{
private:
TEdit *edResult; //自定義區域性變數
String strResult;
protected:
void __fastcall Execute();
void __fastcall ShowResult(); //自定義函式
public:
__fastcall TMyThread(bool CreateSuspended,TEdit *AEdit); //注意:修改了預設引數
};
//---------------------------------------------------------------------------
#endif
//Unit2.cpp //執行緒類實現檔案
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall TMyThread::TMyThread(bool CreateSuspended,TEdit *AEdit)
: TThread(CreateSuspended)
{
edResult=AEdit;
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
for(int i=0;i<200;i++)
{
strResult=IntToStr(i);
Synchronize(ShowResult); //管理執行緒同步,保證安全性
Sleep(100);
}
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::ShowResult()
{
edResult->Text=strResult;
}
//---------------------------------------------------------------------------
然後我們F9執行程式就可以檢視效果了。
二、編寫執行緒函式
Execute()函式就是執行緒函式,它包含了程式中所有需要並行執行的程式碼。除了共享相同的程序空間外,可以認為執行緒就是通過應用程式啟動的程式。但在 編寫執行緒函式的時候需要注意與單獨程式的不同之處。因為執行緒與其他執行緒共享記憶體空間,所以必須確認沒有覆蓋應用程式中其它執行緒的記憶體地址。而另一方面,可 以使用共享記憶體線上程之間進行通訊。
線上程函式內部,我們可以使用任意的全域性變數,但有些變數我們並不希望同一執行緒類的其他例項共享它,就可以宣告一個執行緒(thread-local)變 量。通過將__thread修飾語加入變數宣告就可以宣告一個執行緒變數。例如 int __thread x; 宣告一個整型變數。
__thread修飾語只可用於全域性(檔案範圍)或靜態變數。指標和函式變數不能作為執行緒變數。使用“在寫入時複製”語法的類,如AnsiStrings也不能作為執行緒變數。需要在執行時進行初始化或析構的型別也不能被宣告為__thread型別。
當程式中呼叫Resume()函式時,執行緒啟動並繼續執行直到Execute()結束。這就是執行緒執行特定任務,並在其完成時終止的模式。然而,有時應用 程式需在一些外部條件滿足時終止執行緒。通過檢查Terminated屬性可允許其它執行緒通知本執行緒終止。當其它執行緒試圖終止本執行緒時,它呼叫 Terminate()函式。Terminate()函式將本執行緒的Terminated屬性設定為true。Execute()函式通過檢查和響應 Terminated屬性來實現Terminate()函式。下面的例項演示了這種做法:
void __fastcall TMyThread::Execute()
{
while( !Terminated )
{
}
}
線上程函式終止時我們可能需要做一些清理工作。由於線上程終止前,OnTerminate事件會發生,所以我們可以將清理程式碼放在OnTerminate 事件處理程式中,這樣可確保不管Execute()函式如何執行,清理程式碼總是可以被執行。要注意OnTerminate事件處理程式不作為執行緒的一部分 執行,而是在應用程式的主執行緒中執行的。這意味著:
(1)在OnTerminate事件處理程式中不能使用任何執行緒區域性變數。
(2)在OnTerminate事件處理程式中可安全地訪問任何元件及VCL物件而不會和其他執行緒發生衝突。
三、協調執行緒
在編寫執行緒執行時執行的程式碼時,必須考慮到可能同步執行的其他執行緒行為。主要有兩種情況:一個是避免兩個執行緒試圖同時使用某一個全域性物件或變數;另一個是某執行緒中的一些程式碼可能會依賴其他執行緒所執行任務的結果。
1,避免同時訪問
為避免在訪問全域性物件或變數時與其他執行緒發生衝突,可能需要暫停其他執行緒的執行,直到該執行緒程式碼完成操作。這裡需要注意,不要暫停其他不需停止的執行緒執行,這樣會使效率嚴重降低,也無法獲得使用多執行緒的優點。
<1>,鎖定物件
一些物件內建了鎖定功能,以防止其他執行緒使用該物件的例項。例如,畫布物件(TCanvas及其派生類)有一種Lock()函式可防止其他執行緒訪問畫布,直到呼叫Unlock()函式。
VCL還包含一種執行緒安全的列表物件TThreadList。呼叫TThreadList::LockList()返回列表物件,同時組織其他執行緒使用列 表直到呼叫UnlockList()函式。呼叫TCanvas::Lock()函式或TThreadList::LockList()函式時可以安全地嵌 套。鎖定直到最後一個鎖定呼叫匹配到同一執行緒中相應的解鎖呼叫時才會被釋放。
顯然這種方法只對部分類有效。
<2>,使用重要區段
若物件沒有提供內建的鎖定功能,可使用重要區段。重要區段像門一樣,每次只允許一個執行緒進入。要使用它,需建立TCriticalSection的全域性實 例。TCriticalSection有兩個函式:Acquire()(阻止其他執行緒執行該區段)以Release()(取消對其他執行緒的阻止)。
每個重要區段都與需要保護的全域性記憶體關聯。每個要訪問這個全域性記憶體的執行緒首先要呼叫Acquire()函式以確保其他執行緒不能訪問它。當執行緒結束時,要呼叫Release()函式以便其他執行緒能繼續訪問。
例如,應用程式有一個全域性重要區段變數pLockXY,可阻止訪問全域性變數X和Y。任何使用X或Y的執行緒必須呼叫重要區段,如下所示:
pLockXY->Acquire();
try{
Y=sin(X);
}
__finally
{
pLockXY->Release();
}
<3>,使用多重讀、獨佔寫的同步器
當使用重要區段來保護全域性記憶體時,每次只有一個執行緒可以使用該內容。這種保護可能超出了需要,特別是當有一個經常讀但很少寫的物件或變數時更是如此。多個 執行緒同時讀相同記憶體但沒有執行緒寫記憶體是沒有危險的。當有一些經常被讀但很少有執行緒向其寫入的全域性記憶體時,可使用 TMultiReadExclusiveWriteSynchronizer物件保護它。這個物件與重要區段一樣,但它允許多個執行緒同時讀,只要沒有執行緒 寫即可。執行緒必須有獨佔訪問權才能寫使用TMultiReadExclusiveWriteSynchronizer保護的記憶體。
要使用“多重讀、獨佔寫”的同步器,需建立TMultiReadExclusiveWriteSynchronizer的一個全域性例項,它與要保護的全域性 記憶體關聯。每個需要讀記憶體的執行緒首先要呼叫BeginRead()函式。它確保當前無其它執行緒寫記憶體。執行緒完成讀操作後呼叫EndRead()函式。任何 執行緒要寫記憶體的時候必須先呼叫BeginWrite()函式,結束後呼叫EndWrite()函式。
<4>,共享記憶體的其他技術
當使用VCL物件時,使用主VCL執行緒來執行程式碼,可確保物件不會間接地訪問同時被其他執行緒中的VCL物件使用的記憶體。若全域性變數不需要被多個執行緒共享,可使用執行緒變數來代替它。執行緒可以不需要等待或暫停其他執行緒。
2,等待其他執行緒
若執行緒必須等待另一執行緒完成某項任務,可讓執行緒臨時中斷執行。然後要麼等待另一執行緒完全執行結束,要麼等到另一執行緒通知完成了該項任務。
<1>,等待執行緒執行結束
要等待另一執行緒執行結束,使用它的WaitFor()函式。WaitFor()函式直到那個執行緒終止才返回,終止的方式要麼完成了Execute()函式,要麼由於一個異常。例如,下面的程式碼在訪問列表中的物件前等待,直到另一執行緒填滿該列表。
void __fastcall TVisitList::Execute()
{
int fileRes;
TFillThread *fl=new TFillThread(false);
fillRes=f1->WaitFor();
//以下進行後續處理
}
上例中,列表物件只在WaitFor()函式指出該列表被填滿時才能被訪問。返回值由被等待執行緒的Execute()函式指定。然而,因為呼叫 WaitFor()函式的執行緒需要直到另一執行緒的執行結果,無法以程式碼呼叫Execute()函式,Execute()函式也無法返回任何值。所以 TFillThread執行緒的Execute()函式應該設定ReturnValue屬性。ReturnValue通過被其他執行緒呼叫的 WaitFor()函式返回。返回值是一個證書,由應用程式確定其含意。
<2>,等待任務完成
有時,只需等待執行緒完成一些操作而不是執行結束。為此,可使用一個事件物件。事件物件(TEvent)應具有全域性範圍以便他們能夠為所有執行緒可見。當一個 執行緒完成一個被其他執行緒依賴的操作時,呼叫TEvent::SetEvent()函式。它發出一個訊號,以便任何其他執行緒可檢查並得知操作完成。要關掉信 號則使用ResetEvent()函式。
四、除錯多執行緒程式
當除錯多執行緒應用程式時,試圖跟蹤所有並行執行緒的狀態,或在斷點停止時判斷是哪一個執行緒的執行往往會使人感到迷惑。可使用Thread Status框來幫助跟蹤並控制應用程式中所有的執行緒。開啟Thread Status框的方法是:View|Debug Windows|Threads。
當一個除錯事件(斷點、異常、暫停)發生時,執行緒狀態指示各個執行緒的狀態。右擊可定位相應的原始碼位置或將其他執行緒設定為當前執行緒等。
最後要提醒的是,不要使用無意義的多執行緒。如果一段程式完全是序列的,每一步的操作都需要上一步的結果,那麼在這裡採用多執行緒技術就是毫無意義的。
相關推薦
在BCB中使用多執行緒例項
多執行緒程式設計是提高系統資源利用率的一種常見方式。它佔用的資源更小,啟動更快,還可以實現在後臺執行一些需時較長的操作。一、初識TThread物件VCL提供了用於多執行緒程式設計的TThread類,在這個類中封裝了Windows關於執行緒機制的Windows API,通常將
執行緒池中多執行緒設定超時退出監控
前言 在寫多執行緒程式時,大多數情況下會先excutor建立執行緒池,然後再建立執行緒,但是對一些讀資料庫或者其他IO操作,容易堵住執行緒,此時就需要給執行緒設定超時時間,幹掉超時的執行緒再重新拉起一個執行緒來,但是java執行緒建立並沒有預留超時引數,研究了一下網上也沒找到
觀察者模式中多執行緒執行訂閱事件並順序執行的問題
對事件釋出訂閱模式中啟動執行緒執行操作,但又要保證執行緒順序執行的一些思考和實踐,在開發過程中,經常會遇到需要使用事件來觸發方法執行的情況,比如CS中按鈕的點選事件,滑鼠移動事件,鍵盤監聽事件等等,有時候需要執行比較耗時的任務,但並不希望阻塞主執
Spring4.x中多執行緒使用
直接上程式碼: 一:配置類 import java.util.concurrent.Executor; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springfram
java中多執行緒一定快嗎?看完就知道!!!
理解上下文切換 即使是單核處理器也支援多執行緒執行程式碼,CPU通過每個執行緒分配CPU時間片來實現這個機制.時間片是CPU分配給多個執行緒的時間,因為時間片非常短,所以CPU通過不停的切換執行緒執行,讓我們感覺多個執行緒是同時執行的,時間片一般是幾十毫秒(ms).
Python中多執行緒總結
Python中的多執行緒 多執行緒 一個程序中有多個執行緒就是多執行緒。 一個程序中至少有一個執行緒,並作為程式的入口,這個就是主執行緒。一個程序至少有一個主程序,其他執行緒稱為工作執行緒。 執行緒安全:執行緒執行一段程式碼,不會產生不確定的結果,那這段程式碼就是執行緒安全。(例如pr
Python多執行緒例項
相關文件 Python多執行緒的實現和原理 執行緒與程序 執行緒是程序內一個執行單元,也是程序內的可排程實體。 執行緒與程序的區別: 地址空間,程序獨立空間,執行緒共享程序內的地址空間 資源分配,程序是系統資源排程及分派的基本單位 執行緒是處理器排程的
python(2.7)中多執行緒使用舉例
python(2.7)中多執行緒使用舉例 python27中多執行緒使用舉例 下邊的程式碼都不難理解,不做多餘解釋。唯一有困惑的地方已經在原始碼中註釋說明。這裡也不做多執行緒編碼知識的講解。把這幾種形式(主要是第三種)練成muscle mem
一個Python多執行緒例項
水果分配的問題: 桌上有一隻盤子,每次只能放入5只水果。爸爸專放蘋果, 媽媽專放橘子,一個兒子專等吃盤子中的橘子,一個女兒專等吃盤子中的蘋果.用P,V操作實現爸爸、媽媽、兒子、女兒程序的同步控制。 貼一下程式碼: import random import threa
python中多執行緒中event的使用-----------------即一個靈活的方法標誌位,類似於java的等待喚醒機制(python與java不同的地方)
event是python中一個特有的標誌位方法,他一共有三種方法 1.event.wait():如果標誌位設定了,它不做任何事,如果沒有設定,則將會鎖住,等待標誌位的設定 2.event.set():設定標誌位 3.event.clear():清除標誌位 這一種機制很
python中多執行緒開啟的兩種方式(內含有event的應用,即安全的機制,類似於java的等待喚醒機制,不會出現多個執行緒之間的錯亂問題)
event是類似於java中的等待喚醒機制,具體方法參照上一篇CSDN 下面來介紹開啟執行緒的第一種方式 #Filename:threading1.py #開啟執行緒的第一種方式 import threading import time event=threadin
c++多執行緒例項
主要總結了基於C++的多執行緒函式CreateThread,互斥鎖(或者稱資源獨佔)函式CreateMutex,等待資源函式WaitForSingleObject,關閉執行緒函式(其實是關閉執行緒的控制代碼)CloseHanlde,釋放互斥鎖函式ReleaseMutex的
Android中多執行緒通訊:Handler的理解
Android中的Handler Android中Handler在我理解主要是為了解決執行緒間通訊。 使用Android的Handler機制主要要了解幾個類: Looper: 一個執行緒對應一個或者0個Looper,主執行緒在ActivityThread的時候會預設建立一個L
以單例模式為例,在Idea中多執行緒debug
我們以單例模式的懶漢式在idea中進行多執行緒debug 一是可以學習多執行緒debug,二是可以瞭解懶漢式的執行緒不安全的原因 首先我們建立一個單例懶漢式,然後建立兩個執行緒 程式碼如下: 然後 進行多執行緒debug,來干預懶漢式的執行順序
python中多執行緒與多程序的選擇問題
多執行緒與多程序的選擇問題 既然python中多執行緒和多程序都能夠進行非同步操作,那麼到底應該如何選擇 首先我們必須知道GIL全域性解釋鎖對執行緒的影響,其同一時間只能夠允許一個執行緒進入cpu進行執行,因此對於cpu密集型的程式並不適用於多執行緒操作 cpu密集型的功能對cp
Java中多執行緒併發體系知識點彙總
一、多執行緒 1、作業系統有兩個容易混淆的概念,程序和執行緒。 程序:一個計算機程式的執行例項,包含了需要執行的指令;有自己的獨立地址空間,包含程式內容和資料;不同程序的地址空間是互相隔離的;程序擁有各種資源和狀態資訊,包括開啟的檔案、子程序和訊號處理。 執行緒:表示程
201711671125 Java多執行緒例項(第十一週)
建立3個售票視窗同時開始銷售10張票。 原始碼: public class One { public static void main(String[] args) { Ti
linux下一個程序中多執行緒的資源共享
在說執行緒資源共享之前,我們先來說來說一下執行緒的概念,執行緒是程序內部的一條執行序列(即執行流),一個程序至少有一個執行緒,即main函式代表的執行流。當然我們也可以通過執行緒庫來建立新的執行緒,這種執行緒我們稱之為函式執行緒,同一個程序中的所有普執行緒是併發執行的。而這些
java中多執行緒的建立和啟動(1)
多執行緒概述 1.什麼是多執行緒 執行緒是程式執行的一條路徑,一個程序中可以包含多條執行緒;多執行緒併發執行可以提高程式的效率 2.程序和執行緒之間的關係 作業系統可以同時執行多個任務,每個任務就是程序;程序可以同時執行多個任務,每個任務就是執
Java進階(四十二)Java中多執行緒使用匿名內部類的方式進行建立3種方式
Java中多執行緒使用匿名內部類的方式進行建立3種方式 package cn.edu.ujn.demo; // 匿名內部類的格式: public class ThreadDemo {