在软件开发的过程中,多线程的开发应用有着极为重要的位置,使用多线程可以让软件系统
能够并行操作、同时也能提高其运行效率。作为软件开发人员的必修课之一,多线程的熟练
运用可以让软件系统有更佳的性能表现。
以下使用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.