• 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);
    begin
    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;
    var
     i: DWord;
     IsQuit: Boolean;
    begin
     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;
    end;
    (6)线程同步。
    如果线程要调用VCL里面的内容(如:别的窗体中的控件),就需要将这个线程同步。线程同步表示交由主线程运行这段代码,各个线程都在主线程中分时间段运行。另外,要想避免多个线程同时执行同一段代码也需要将多线程同步。
    临界区和互斥的作用类似,都是用来进行同步的,但它们间有以下一点差别:
    临界区只能在进程内使用,也就是说只能是进程内的线程间的同步;而互斥则还可用在进程之间的;临界区所花消的时间很少,才10~15个时间片,而互斥需要400多个;临界区随着进程的终止而终止,而互斥,如果你不用closehandle()的话,在进程终止后仍然在系统内存在,也就是说它是系统全局对象;
    同步的方法有:

    (1)使用临界区对象。
    临界区对象有两种:TRTLCriticalSection 和 CriticalSection。
      TRTLCriticalSection的用法

    var
     GlobalVariable:Double;

    var
     CriticalSection:TRTLCriticalSection;

    procedure SetGlobalVariable(Value:Double);
    begin
     EnterCriticalSection(CriticalSection);   //进入临界区
     try
       GlobalVariable:=Value;
     finally
       LeaveCriticalSection(CriticalSection);  //离开临界区
     end;
    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;

    type
      TMyThread = class(TThread)
      private

      protected
        procedure Execute; override;
      public

        constructor Create; virtual;
      end;

    var
      Form1 : TForm1;
      HSem : THandle = 0 ;
    implementation

    {$R *.dfm}

    var
      tick: Integer = 0;
    procedure TMyThread.Execute;
    var
      WaitReturn : DWord ;
    begin
      WaitReturn := WaitForSingleObject(HSem,INFINITE) ;
      Form1.Edit1.Text := IntToStr(tick);
      Inc(tick);
      Sleep(10);
      ReleaseSemaphore(HSem, 1, Nil)
    end;

    constructor TMyThread.Create;
    begin
      inherited Create(False);
      FreeOnTerminate := True;
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      HSem := CreateSemaphore(Nil,1,1,Nil) ;
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      CloseHandle(HSem) ;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
      index: Integer;
    begin
      for index := 0 to 10 do
      begin
        TMyThread.Create;
      end;
    end;

    end.
    一般的同步对象使用Mutex对象,是因为Mutex有一个特别之处:当一个持有对象的线程DOWN掉的时候,mutex对象可以自动让其它等待这个对象的线程接受,而其它的内核对象则不具体这个功能。
    之所要使用Semaphore则是因为Semaphore可以提供一个活动线程的上限,即lMaximumCount参数,这才是它的真正有用之处。
  • 相关阅读:
    C#+API实现指定窗体激活
    DEVC++学习之(一)
    javascript 实现原生下载的各种情况
    IssueVision 之WebService安全篇
    Add relationship to BS sample
    ExpandRelationWithCtxt 与 GetRelatedObjects 的区别
    C#调用javascript
    解禁网页限制
    Unix cc options vs gcc options
    IssueVision 之模式篇
  • 原文地址:https://www.cnblogs.com/taobataoma/p/858373.html
Copyright © 2020-2023  润新知