天天看点

Delphi多线程编程中的技巧

(1)创建线程

MsgThread := TMsgThread.Create(False) ;    //创建并执行线程

MsgThread := TMsgThread.Create(True) ;   //创建线程后挂起

constructor Create(CreateSuspended: Boolean); 中的参数CreateSuspended表示创建后是否挂起线程。

(2)设置线程里没有设置循环执行的话,且设置FreeOnTerminate为True,则线程执行完后就会自己释放。

(3)在一个线程结束后,调用另一个事件的方法:

只要设置Onterminate:=某方法,这样在线程结束前自然会被调用,比如 :

procedure TSendShortMessageThread.Execute; 

var 

 Bitmap: Tbitamp; 

begin 

Bimap:=Tbitmap.create(nil) ;

OnTerminate:=Threaddone; 

end; 

procedure Threaddone(sender: tobject); 

Bimap.Free;   //在Destory之前会被调用 

end;

(4)程序结束前安全的退出线程的方法:

     if MsgThread <> nil then

   begin

     MsgThread.Terminate ;

     MsgThread.WaitFor ;

   end;

(5)判断当前线程的状态:

//以下资料来自大富翁论坛。

/判断线程是否释放 

//返回值:0-已释放;1-正在运行;2-已终止但未释放; 

//3-未建立或不存在 

function TFrmMain.CheckThreadFreed(aThread: TThread): Byte; 

 i: DWord; 

 IsQuit: Boolean; 

 if Assigned(aThread) then 

 begin 

   IsQuit := GetExitCodeThread(aThread.Handle, i); 

   if IsQuit then           //If the function succeeds, the return value is nonzero. 

                                 //If the function fails, the return value is zero. 

   begin 

     if i = STILL_ACTIVE then    //If the specified thread has not terminated, 

                                 //the termination status returned is STILL_ACTIVE. 

       Result := 1 

     else 

       Result := 2;              //aThread未Free,因为Tthread.Destroy中有执行语句 

   end 

   else 

     Result := 0;                //可以用GetLastError取得错误代码 

 end 

 else 

   Result := 3; 

(6)线程同步。

如果线程要调用VCL里面的内容(如:别的窗体中的控件),就需要将这个线程同步。线程同步表示交由主线程运行这段代码,各个线程都在主线程中分时间段运行。另外,要想避免多个线程同时执行同一段代码也需要将多线程同步。

临界区和互斥的作用类似,都是用来进行同步的,但它们间有以下一点差别:

临界区只能在进程内使用,也就是说只能是进程内的线程间的同步;而互斥则还可用在进程之间的;临界区所花消的时间很少,才10~15个时间片,而互斥需要400多个;临界区随着进程的终止而终止,而互斥,如果你不用closehandle()的话,在进程终止后仍然在系统内存在,也就是说它是系统全局对象;

同步的方法有:

(1)使用临界区对象。

临界区对象有两种:TRTLCriticalSection 和 CriticalSection。

  TRTLCriticalSection的用法

 GlobalVariable:Double; 

 CriticalSection:TRTLCriticalSection; 

procedure SetGlobalVariable(Value:Double); 

 EnterCriticalSection(CriticalSection);   //进入临界区

 try 

   GlobalVariable:=Value; 

 finally 

   LeaveCriticalSection(CriticalSection);  //离开临界区

 end; 

initialization 

 InitializeCriticalSection(CriticalSection);  //初始化

finalization 

 DeleteCriticalSection(CriticalSection); //删除

end.

  CriticalSection(重要区段)的用法:

var criticalsection: TCriticalsection;

创建:criticalsection := TCriticalsection.create;

使用:

criticalsection.enter;

try

  ...

finally

  criticalsection.leave;

end;     

   (2)使用互斥

先在主线程中创建事件对象:

var

  hMutex: THandle = 0;

 hMutex := CreateMutex(nil, False, nil);

 在线程的Execute方法中加入以下代码:

if WaitForSingleObject(hMutex, INFINITE) = WAIT_OBJECT_0 then

  //Do Something;

ReleaseMutex(hMutex);

最后记得要释放互斥对象:

CloseHandle(hMutex);

(3)使用信号量

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

  Dialogs, ExtCtrls, StdCtrls;

type

  TForm1 = class(TForm)

    Edit1: TEdit;

    Button1: TButton;

    procedure FormCreate(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

    procedure Button1Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

  TMyThread = class(TThread)

  protected

    procedure Execute; override;

    constructor Create; virtual;

  Form1 : TForm1;

  HSem : THandle = 0 ;

implementation

{$R *.dfm}

  tick: Integer = 0;

procedure TMyThread.Execute;

  WaitReturn : DWord ;

begin

  WaitReturn := WaitForSingleObject(HSem,INFINITE) ;

  Form1.Edit1.Text := IntToStr(tick);

  Inc(tick);

  Sleep(10);

  ReleaseSemaphore(HSem, 1, Nil)

constructor TMyThread.Create;

  inherited Create(False);

  FreeOnTerminate := True;

procedure TForm1.FormCreate(Sender: TObject);

  HSem := CreateSemaphore(Nil,1,1,Nil) ;

procedure TForm1.FormDestroy(Sender: TObject);

  CloseHandle(HSem) ;

procedure TForm1.Button1Click(Sender: TObject);

  index: Integer;

  for index := 0 to 10 do

  begin

    TMyThread.Create;

一般的同步对象使用Mutex对象,是因为Mutex有一个特别之处:当一个持有对象的线程DOWN掉的时候,mutex对象可以自动让其它等待这个对象的线程接受,而其它的内核对象则不具体这个功能。

之所要使用Semaphore则是因为Semaphore可以提供一个活动线程的上限,即lMaximumCount参数,这才是它的真正有用之处。

    本文转自 OldHawk  博客园博客,原文链接:http://www.cnblogs.com/taobataoma/archive/2007/08/16/858373.html,如需转载请自行联系原作者

继续阅读