百度首页 | 百度空间
 
查看文章
 
多线程的使用(Delphi)
2008-02-26 00:53
****************************************************************

****************************************************************
TThread在Classes单元中声明,直接从TObject继承下来的,因为,它不是组件.TThread是个抽象类,所以不能创建TThread的实例,而只能创建其派生类的实例.

利用TThread类来编写多线程应用程序的一般步骤如下:

[步骤一] 从TThread类派生出一个新的线程类.
[步骤二] 创建线程对象
[步骤三] 设置线程对象的属性,比如优先级等.
[步骤四] 根据具体情况挂起或唤醒线程.
[步骤五] 结束线程.

从TThread类派生出一个新的线程类的过程非常简单:通常菜单"File|New|Other..."打开"New Items"对话框,选中"New"页的"Thread Object"项,单击"OK"按钮,接着在弹出的"New Thread Object"对话框中输入新的线程类的名称.通常线程类的名称以T开头,以Thread结束,例如"TTestThread".

TThread类还有以下的一些属性、方法和事件:

Priority属性:整型,设置线程的优先级.
Return Value属性:返回值,即当线程结束时返回给其他线程的一个数值.
Suspended属性:判断线程是否被挂起.
ThreadID属性:线程标识号,是整个系统中线程的标识号.
DoTerminate过程:产生一个OnTerminate事件,但是不结束线程的执行.
Resume过程:唤醒一个线程继续执行.
Suspend过程:挂起一个线程.
Synchronize过程:由主VCL线程调用的一个同步过程.
Terminate过程:将Terminated属性设置为True,终止线程的执行.
WairFor方法:等待线程的终止并返回Return Value属性的数值.



举例:

建立TThread类代码


unit Unit2;

interface

uses
   Classes;

type
   TPainterThread = class(TThread)
   private
     { Private declarations }
   protected
     procedure Execute; override;
   end;

implementation

uses unit1,graphics;//使用了unit1单元(也就是form单元)    使用了graphics单元(图像单元,后面clblue会使用)

procedure TPainterThread.Execute;
var
   x,y:integer;
begin
randomize;//初始化随机函数
repeat
   x:=random(300);
   y:=random(form1.ClientHeight);
   with form1.Canvas do
   begin
     lock;//锁定画布
     try
       pixels[x,y]:=clblue;
     finally
       unlock;
     end;
   end;
   until Terminated;
end;

end.


form调用TThread方法举例:

在form上建立两个button组件.

unit Unit1;

interface

uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, Unit2;//引用线程所在的实例

type
   TForm1 = class(TForm)
     Button1: TButton;
     Button2: TButton;
     procedure Button1Click(Sender: TObject);
     procedure Button2Click(Sender: TObject);
   private
     pt:TPainterThread;
  
   public
   end;

var
   Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
pt:=TPainterThread.Create(false);   //开始绘图线程
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
pt.Free;
end;

end.





多线程程序访问VCL的时候要特别注意,只能逐个地实现对VCL的访问.具体可以采用下面的两个方法:
(1) 锁定VCL对象
对于一些具有锁定功能的对象,可以在锁定之后再进去具体操作,比如上面的方法!!!.
(2) 使用Synchronize函数
TThread类的Synchronize过程声明如下:

type TThreadMethod=procedure of object;
procedure Synchronize(Method:TThreadMethod);

其他参数Method为一个不带参数的过程名.在这个不带参数的过程中是一些访问VCL的代码.
对Synchronize的调用是在Execute过程中,用来避免对VCL的并发访问.程序运行期间的具体过程实际上是由Synchronize过程来通知主线程,然后主线程在适当的时机执行Synchronize过程的参数列表中不带参数的过程.在多个线程的情况下,主线程将Synchronize过程所发的通知放到消息队列中,然后逐个地响应这些消息.通过这种机制Synchronize实现了线程之间的同步.


举例:

(一)在窗体上放置一个Imagelist,两个label,一个SpinEdit组件(在"Samples"页),一个Button.为Imagelist装载一系列的动画位图,Button的Caption为"开始".

(二)在单元中的type部分声明一个线程TAnimThread如下:
type
     TAnimThread=class(TThread)
     private
         b:TBitMap;
         procedure DrawAnimPic;
     protected
         procedure Execute; override;
     end;

在窗体的Private部分声明一个TAnimThread的实例:
AnimThread:TAnimThread;

并在Var部分定义全局变量
run:Boolean;

(三)在单击按钮时创建TAnimThread的实例,并立即执行该线程.同时处理窗体组件的事件.具体过程参见程度清单如下:

unit Unit1;

interface

uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, Spin, ImgList;

type
     TAnimThread = class(TThread)      //声明一个线程
     private
         b:TBitMap;
         procedure DrawAnimPic;
     protected
         procedure Execute; override;
   end;

     TAnimWindow = class(TForm)
     ImageList1: TImageList;
     SpinEdit1: TSpinEdit;
     Button1: TButton;
     procedure Button1Click(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure SpinEdit1Change(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
   private
     AnimThread:TAnimThread;            //创建一个线程实例
   public
     { Public declarations }
   end;

var
   AnimWindow: TAnimWindow;
   run: Boolean;
implementation

{$R *.dfm}

procedure TAnimThread.Execute;
var
   x,i:integer;
   dir:Boolean;
begin
b:=TBitMap.Create;
b.width:=animwindow.width;
b.height:=32;
b.canvas.pen.color:=clpurple;
b.canvas.brush.color:=clskyblue;
b.canvas.rectangle(0,0,animwindow.width,32);
dir:=false;
x:=0;
i:=0;
repeat
begin
     inc(i);
     b.canvas.rectangle(0,0,animwindow.width,32);
     animwindow.imagelist1.draw(b.canvas,x,0,i);
     synchronize(Drawanimpic);
     sleep(animwindow.spinedit1.value);
     if(x=0) or (x=300) then
         dir:=not dir;
     if dir then inc(x) else dec(x);
     if i>=animwindow.imagelist1.count-1 then
         i:=0;
     end;
until Terminated;
b.free;
end;

procedure TAnimThread.DrawAnimPic;
begin
//双缓冲技术
Animwindow.Canvas.CopyRect(bounds(0,0,animwindow.Width,32),b.Canvas,bounds(0,0,animwindow.Width,32));
bitblt(animwindow.Canvas.Handle,0,0,animwindow.Width,32,b.Canvas.Handle,0,0,SRCCOPY);
end;

procedure TAnimWindow.Button1Click(Sender: TObject);
begin
run:=not run;
if run then
     animthread:=tanimthread.create(false)
else
     animthread.free;
if button1.caption='开始' then
     button1.caption:='结束'
else
     button1.caption:='开始';
end;

procedure TAnimWindow.FormCreate(Sender: TObject);
begin
run:=false;
end;

procedure TAnimWindow.SpinEdit1Change(Sender: TObject);
begin
if spinedit1.value<10 then
begin
     button1click(self);
showmessage('延时时间太短!可能影响动画效果!');
end;
end;

procedure TAnimWindow.FormDestroy(Sender: TObject);
begin
if not animthread.terminated then
     animthread.free;
end;

end.


DrawAnimPic过程使用了双缓冲技术,即在后台创建一个位图,将所要显示的图片拷贝到该位图上,然后再把该位图拷贝到前右的窗体上,因为该位图不显示,所以窗体不会有闪烁现象.

动画播放经常要用到Sleep函数,其功能就是将当前线程挂起一定的时间间隔.声明如下:
VOID Sleep(
     DWORD dwMilliseconds   //sleep time in milliseconds
);
其中dwMilliseconds为间隔时间,单位为毫秒.

类别:多线程编程 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码:
 

     

©2008 Baidu