在軟體開發的過程中,多線程的開發應用有著極為重要的位置,使用多線程可以讓軟體系統
能夠並行操作、同時也能提高其運行效率。作為軟體開發人員的必修課之一,多線程的熟練
運用可以讓軟體系統有更佳的效能表現。
以下使用Window Api、Delphi 封裝的TThread類來分別建立線程,再以普通方法來執行
一個耗時的過程,對比使用線程的好處。
1. Windows API 函數直接建立
主要是CreateThread 函數,其函數式如下:
HANDLE CreateThread(
// 安全執行緒屬性,預設用Nil
LPSECURITY_ATTRIBUTES lpThreadAttributes,
// 線程分配的堆棧大小,預設為0,系統自動分配
DWORD dwStackSize,
// 線程函數入口地址,要求是不帶參數的全域性的方法
LPTHREAD_START_ROUTINE lpStartAddress,
// 傳遞給線程的參數值
LPVOID lpParameter,
// 建立線程的標識,如CREATE_SUSPENDED (掛起)
DWORD dwCreationFlags,
//返回的線程標識identifier
LPDWORD lpThreadId
);
如果線程建立成功,傳回值為其控制代碼值 .
在Delphi 項目中建立一個表單,寫下以下線程函數,以便調用
procedure APIThread1;
var i,cId:Integer;
begin
with Form2 do
begin
for i:=1 to imax do
begin
EnterCriticalSection(Rtl);
cId := GetCurrentThreadId ; //擷取當前執行的線程標識
Memo1.Lines.Add('Thread ID '+inttostr(cId)+ ' : '+inttostr(i));
LeaveCriticalSection(Rtl);
end;
end;
end;
為防止多個線程同時訪問(讀寫)同一個VCL資源引起出錯,使用了臨界變數 Rtl,
所以要聲明一個局部的臨界變數
Var
Rtl : TRTLCriticalSection;
其作用相當於一個協議鎖,比如: 當APIThread1 函數,被CreateThread
(nil,0,@APIThread1,nil,0,hid)
調用多次產生不同線程時,由雩都對Memo1 執行了寫入操作,其中一個線程在寫入的過
程中,用Rtl臨界變數告訴其它正要訪問的線程:"我正在使用,請稍等。"
注意:
進入臨界區EnterCriticalSection(Rtl) 和離開臨界區LeaveCriticalSection(Rtl)是
配對的,所以要確保正常進入,正常離開,在使用臨界區變數前,必需先初始化,
InitializeCriticalSection(Rtl),用完後釋放DeleteCriticalSection(Rtl);
2. 使用Delphi 封裝的TThread 類建立
主要是繼承TThread 類,在TThread 類的核心方法Execute中執行你想要的作業碼.
其實,通過查看TThread 類的原始碼可知,TThread同樣是調用CreateThread函數建立線
程,只是封裝/簡化了部分線程的應用細節,同時也納入部分安全考慮,這無疑為開發人
員提供了調用上的方便。
方法中常用的線程掛起Suspend,喚醒Resume,中止Terminate等方法,可查閱相關
資料說明,這裡僅作線程的簡單調用例子。
先聲明繼承類
type
TMyThread =class(TThread)
private
FFlag:Integer;
procedure AccessVcl;
protected
procedure Execute ; override;
public
constructor Create(aFlag:Integer);
end;
在implementation部分寫下方法內容
constructor TMyThread.Create(aFlag: Integer);
begin
inherited Create(Suspended) ;
FreeOnTerminate := true;
FFlag := aFlag;
end;
procedure TMyThread.Execute;
begin
inherited;
AccessVcl;
//Synchronize(AccessVcl);
end;
procedure TMyThread.AccessVcl;
var i:Integer;
begin
with Form2 do
begin
for i:=1 to iMax do
Memo1.Lines.Add('My Thread '+Inttostr(FFlag)+' : '+inttostr(i));
end;
end;
調用執行線程:TMyThread.Create(10);
3. 再寫一個普通的for 迴圈執行某個比較花費時間的操作方法
for i:=1 to imax do
begin
cId := GetCurrentThreadId ;
Memo1.Lines.Add('Thread ID '+inttostr(cId)+ ' : '+inttostr(i));
end;
在表單上分別調用API 線程方法,Delphi TThread 線程類方法,普通操作方法,再比較
執行效果,即時可以體現線程方法與非線程的好處。
全部源碼如下:
view plaincopy to clipboardprint?
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm2 = class(TForm)
Memo1: TMemo;
BtnThread1: TButton;
BtnThread2: TButton;
BtnNoThread: TButton;
Button1: TButton;
BtnClear: TButton;
BtnMyThread: TButton;
Button2: TButton;
procedure BtnThread1Click(Sender: TObject);
procedure BtnThread2Click(Sender: TObject);
procedure BtnNoThreadClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure BtnClearClick(Sender: TObject);
procedure BtnMyThreadClick(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
{繼承的線程類}
type
TMyThread =class(TThread)
private
FFlag:Integer;
procedure AccessVcl;
protected
procedure Execute ; override;
public
constructor Create(aFlag:Integer);
end;
const
iMax = 2000 ;
var
Form2: TForm2;
Rtl : TRTLCriticalSection;
Thd1,Thd2 : Cardinal;
implementation
{$R *.dfm}
//API 線程方法
procedure APIThread1;
var i,cId:Integer;
begin
with Form2 do
begin
for i:=1 to imax do
begin
EnterCriticalSection(Rtl);
cId := GetCurrentThreadId ;
Memo1.Lines.Add('Thread ID '+inttostr(cId)+ ' : '+inttostr(i));
LeaveCriticalSection(Rtl);
end;
end;
end;
constructor TMyThread.Create(aFlag: Integer);
begin
inherited Create(Suspended) ;
FreeOnTerminate := true;
FFlag := aFlag;
end;
procedure TMyThread.Execute;
begin
inherited;
AccessVcl;
//Synchronize(AccessVcl);
end;
procedure TMyThread.AccessVcl;
var i:Integer;
begin
with Form2 do
begin
for i:=1 to iMax do
Memo1.Lines.Add('My Thread '+Inttostr(FFlag)+' : '+inttostr(i));
end;
end;
procedure TForm2.BtnThread1Click(Sender: TObject);
var Hid:THandle;
begin
//API線程調用1
Thd1:= CreateThread(nil,0,@APIThread1,nil,0,hid);
end;
procedure TForm2.BtnThread2Click(Sender: TObject);
var Hid:THandle;
begin
//API線程調用2
Thd2:= CreateThread(nil,0,@APIThread1,nil,0,hid);
end;
procedure TForm2.BtnNoThreadClick(Sender: TObject);
var i,cid:Integer;
begin
//普通方法執行for 迴圈
for i:=1 to imax do
begin
cId := GetCurrentThreadId ;
Memo1.Lines.Add('Thread ID '+inttostr(cId)+ ' : '+inttostr(i));
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
ShowMessage('同時執行其它操作');
end;
procedure TForm2.BtnClearClick(Sender: TObject);
begin
Memo1.Lines.Clear;
end;
procedure TForm2.BtnMyThreadClick(Sender: TObject);
begin
//Delphi TThread繼承類的調用方法
TMyThread.Create(11);
end;
procedure TForm2.Button2Click(Sender: TObject);
var ext:THandle;
begin
GetExitcodeThread(Thd1,Ext);
TerminateThread(Thd1,ext);
//LeaveCriticalSection(Rtl);
end;
initialization
InitializeCriticalSection(Rtl);
finalization
DeleteCriticalSection(Rtl);
end.