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