• DELPHI 多线程(TThread类的实现)


    DELPHI 多线程(TThread类的实现)

    之前学习了用API实现,让我们再学习下用DELPHI的TThread类。

    先新建一个普通的工程,再新建一个线程类File>>New>>Othre>>Delphi File>Thread Object,取个名字,DELPHI会自动生成一个单元,我们只需往里简单添加功能代码,和在要使用的单元里实例引用即可。

    为了节省篇幅,现把TMyThread类集成主窗体单元里,在窗体单元里声明类也是可以的。

    例:用工作线程在窗体输出0~500000的数字。

     1 unit Unit1;
     2 
     3 interface
     4 
     5 uses
     6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     7   Dialogs, StdCtrls;
     8 
     9 type
    10   TMyThread = class(TThread)
    11   private
    12     { Private declarations }
    13   protected
    14     procedure Execute; override; {执行}
    15     procedure Run; {声明多一个过程,把功能代码写在这里再给Execute调用}
    16   end;
    17   TForm1 = class(TForm)
    18     btn1: TButton;
    19     procedure btn1Click(Sender: TObject);
    20   private
    21     { Private declarations }
    22   public
    23     { Public declarations }
    24   end;
    25 
    26 
    27 
    28 var
    29   Form1: TForm1;
    30 
    31 
    32 implementation
    33 
    34 {$R *.dfm}
    35 
    36 var
    37   MyThread:TMyThread; {声明一个线程类对象]
    38 
    39 procedure TMyThread.Execute;
    40 begin
    41   { Place thread code here }
    42   FreeOnTerminate:=True; {加上这句线程用完了会自动注释}
    43   Run;
    44 end;
    45 
    46 procedure TMyThread.Run;
    47 var
    48   i:integer;
    49 begin
    50   for i := 0 to 500000 do
    51   begin
    52     Form1.Canvas.Lock;
    53     Form1.Canvas.TextOut(10,10,IntToStr(i));
    54     Form1.Canvas.Unlock;
    55   end;
    56 end;
    57 
    58 procedure TForm1.btn1Click(Sender: TObject);
    59 begin
    60   MyThread:=TMyThread.Create(False); {实例化这个类,为False时立即运行,为True时可加MyThread.Resume用来启动}
    61 end;

    CriticalSection(临界区)

     uses SyncObjs;用TCriticalSection类的方法处理。

    例:用三个线程,按顺序给ListBox添加0~99.

     1 unit Unit1;
     2 
     3 interface
     4 
     5 uses
     6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     7   Dialogs, StdCtrls;
     8 
     9 type
    10   TMyThread = class(TThread)
    11   private
    12     { Private declarations }
    13   protected
    14     procedure Execute; override; {执行}
    15     procedure Run;  {运行}
    16   end;
    17   TForm1 = class(TForm)
    18     btn1: TButton;
    19     lst1: TListBox;
    20     procedure btn1Click(Sender: TObject);
    21     procedure FormDestroy(Sender: TObject);
    22   private
    23     { Private declarations }
    24   public
    25     { Public declarations }
    26   end;
    27 
    28 
    29 
    30 var
    31   Form1: TForm1;
    32 
    33 
    34 implementation
    35 
    36 {$R *.dfm}
    37 
    38 uses SyncObjs;
    39 
    40 var
    41   MyThread:TMyThread;   {声明线程}
    42   CS:TCriticalSection; {声明临界}
    43 
    44 
    45 procedure TMyThread.Execute;
    46 begin
    47   { Place thread code here }
    48   FreeOnTerminate:=True; {加上这句线程用完了会自动注释}
    49   Run;     {运行}
    50 end;
    51 
    52 procedure TMyThread.Run;
    53 var
    54   i:integer;
    55 begin
    56   CS.Enter;  {我要用了,其它人等下}
    57   for i := 0 to 100 - 1 do
    58   begin
    59     Form1.lst1.Items.Add(IntToStr(i));
    60   end;
    61   CS.Leave;  {我用完了,下一个}
    62 end;
    63 
    64 procedure TForm1.btn1Click(Sender: TObject);
    65 begin
    66   CS:=TCriticalSection.Create;     {实例化临界}
    67   MyThread:=TMyThread.Create(False); {实例化这个类,为False时立即运行,为True时可加MyThread.Resume用来启动}
    68   MyThread:=TMyThread.Create(False);
    69   MyThread:=TMyThread.Create(False);
    70 end;
    71 
    72 
    73 procedure TForm1.FormDestroy(Sender: TObject);
    74 begin
    75   CS.Free;{释放临界体}
    76 end;
    77 
    78 end.

    Mutex (互斥对象)

    uses SyncObjs;用TMutex类的方法处理(把释放语句放在循环内外可以决定执行顺序)

    例:互斥输出三个0~2000的数字到窗体在不同位置。

     1 unit Unit1;
     2 
     3 interface
     4 
     5 uses
     6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     7   Dialogs, StdCtrls;
     8 
     9 type
    10   TMyThread = class(TThread)
    11   private
    12     { Private declarations }
    13   protected
    14     procedure Execute; override; {执行}
    15     procedure Run;  {运行}
    16   end;
    17   TForm1 = class(TForm)
    18     btn1: TButton;
    19     procedure FormDestroy(Sender: TObject);
    20     procedure btn1Click(Sender: TObject);
    21   private
    22     { Private declarations }
    23   public
    24     { Public declarations }
    25   end;
    26 
    27 
    28 
    29 var
    30   Form1: TForm1;
    31 
    32 
    33 implementation
    34 
    35 {$R *.dfm}
    36 
    37 uses SyncObjs;
    38 
    39 var
    40   MyThread:TMyThread;   {声明线程}
    41   Mutex:TMutex; {声明互斥体}
    42   f:integer;
    43 
    44 
    45 procedure TMyThread.Execute;
    46 begin
    47   { Place thread code here }
    48   FreeOnTerminate:=True; {加上这句线程用完了会自动注释}
    49   Run;     {运行}
    50 end;
    51 
    52 procedure TMyThread.Run;
    53 var
    54   i,y:integer;
    55 begin
    56   Inc(f);
    57   y:=20*f;
    58   for i := 0 to 2000  do
    59   begin
    60     if Mutex.WaitFor(INFINITE)=wrSignaled then   {判断函数,能用时就用}
    61     begin
    62       Form1.Canvas.Lock;
    63       Form1.Canvas.TextOut(10,y,IntToStr(i));
    64       Form1.Canvas.Unlock;
    65       Sleep(1);
    66       Mutex.Release; {释放,谁来接下去用}
    67     end;
    68   end;
    69 end;
    70 
    71 procedure TForm1.btn1Click(Sender: TObject);
    72 begin
    73   f:=0;
    74   Repaint;
    75   Mutex:=TMutex.Create(False);  {参数为是否让创建者拥有该互斥体,一般为False}
    76   MyThread:=TMyThread.Create(False);
    77   MyThread:=TMyThread.Create(False);
    78   MyThread:=TMyThread.Create(False);
    79 end;
    80 
    81 procedure TForm1.FormDestroy(Sender: TObject);
    82 begin
    83   Mutex.Free;{释放互斥体}
    84 end;
    85 
    86 end.

    Semaphore(信号或叫信号量)

     {DELPHI2007不支持信号量,DELPHI2009才开始支持}

     1 unit Unit1;
     2 
     3 interface
     4 
     5 uses
     6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     7   Dialogs, StdCtrls;
     8 
     9 type
    10   TForm1 = class(TForm)
    11     Button1: TButton;
    12     Edit1: TEdit;
    13     procedure Button1Click(Sender: TObject);
    14     procedure FormCreate(Sender: TObject);
    15     procedure FormDestroy(Sender: TObject);
    16     procedure Edit1KeyPress(Sender: TObject; var Key: Char);
    17   end;
    18 
    19 var
    20   Form1: TForm1;
    21 
    22 implementation
    23 
    24 {$R *.dfm}
    25 
    26 uses SyncObjs;
    27 var
    28   f: Integer;
    29   MySemaphore: TSemaphore;
    30 
    31 function MyThreadFun(p: Pointer): DWORD; stdcall;
    32 var
    33   i,y: Integer;
    34 begin
    35   Inc(f);
    36   y := 20 * f;
    37   if MySemaphore.WaitFor(INFINITE) = wrSignaled then
    38   begin
    39     for i := 0 to 1000 do
    40     begin
    41       Form1.Canvas.Lock;
    42       Form1.Canvas.TextOut(20, y, IntToStr(i));
    43       Form1.Canvas.Unlock;
    44       Sleep(1);
    45     end;
    46   end;
    47   MySemaphore.Release;
    48   Result := 0;
    49 end;
    50 
    51 procedure TForm1.Button1Click(Sender: TObject);
    52 var
    53   ThreadID: DWORD;
    54 begin
    55   if Assigned(MySemaphore) then MySemaphore.Free;
    56   MySemaphore := TSemaphore.Create(nil, StrToInt(Edit1.Text), 5, ''); {创建,参数一为安全默认为nil,参数2可以填写运行多少线程,参数3是运行总数,参数4可命名用于多进程}
    57 
    58   Self.Repaint;
    59   f := 0;
    60   CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
    61   CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
    62   CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
    63   CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
    64   CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
    65 end;
    66 
    67 {让 Edit 只接受 1 2 3 4 5 五个数}
    68 procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
    69 begin
    70   if not CharInSet(Key, ['1'..'5']) then Key := #0;
    71 end;
    72 
    73 procedure TForm1.FormCreate(Sender: TObject);
    74 begin
    75   Edit1.Text := '1';
    76 end;
    77 
    78 procedure TForm1.FormDestroy(Sender: TObject);
    79 begin
    80   if Assigned(MySemaphore) then MySemaphore.Free;
    81 end;
    82 
    83 end.

     Event (事件对象)

    注:相比API的处理方式,此类没有启动步进一次后暂停的方法。

      1 unit Unit1;
      2 
      3 interface
      4 
      5 uses
      6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      7   Dialogs, StdCtrls;
      8 
      9 type
     10   TMyThread = class(TThread)
     11   private
     12     { Private declarations }
     13   protected
     14     procedure Execute; override;
     15     procedure Run;
     16   end;
     17 
     18   TForm1 = class(TForm)
     19     btn1: TButton;
     20     btn2: TButton;
     21     btn3: TButton;
     22     btn4: TButton;
     23     procedure btn1Click(Sender: TObject);
     24     procedure FormDestroy(Sender: TObject);
     25     procedure btn2Click(Sender: TObject);
     26     procedure btn3Click(Sender: TObject);
     27     procedure btn4Click(Sender: TObject);
     28     procedure FormCreate(Sender: TObject);
     29   private
     30     { Private declarations }
     31   public
     32     { Public declarations }
     33   end;
     34 
     35 var
     36   Form1: TForm1;
     37 
     38 implementation
     39 
     40 {$R *.dfm}
     41 
     42 uses SyncObjs;
     43 
     44 var
     45   f:integer;
     46   MyEvent:TEvent;
     47   MyThread:TMyThread;
     48 
     49 { TMyThread }
     50 
     51 
     52 procedure TMyThread.Execute;
     53 begin
     54   inherited;
     55   FreeOnTerminate:=True; {线程使用完自己注销}
     56   Run;
     57 end;
     58 
     59 procedure TMyThread.Run;
     60 var
     61   i,y:integer;
     62 begin
     63   Inc(f);
     64   y:=20*f;
     65 
     66   for i := 0 to 20000 do
     67   begin
     68     if MyEvent.WaitFor(INFINITE)=wrSignaled then    {判断事件在用没,配合事件的启动和暂停,对事件相关线程起统一控制}
     69     begin
     70       Form1.Canvas.lock;
     71       Form1.Canvas.TextOut(10,y,IntToStr(i));
     72       Form1.Canvas.Unlock;
     73       Sleep(1);
     74     end;
     75 
     76   end;
     77 
     78 end;
     79 
     80 procedure TForm1.btn1Click(Sender: TObject);
     81 begin
     82   Repaint;
     83   f:=0;
     84   if Assigned(MyEvent) then MyEvent.Free;    {如果有,就先销毁}
     85 
     86   {参数1安全设置,一般为空;参数2为True时可手动控制暂停,为Flase时对象控制一次后立即暂停
     87   参数3为True时对象建立后即可运行,为false时对象建立后控制为暂停状态,参数4为对象名称,用于跨进程,不用时默认''}
     88   MyEvent:=TEvent.Create(nil,True,True,'');   {创建事件}
     89 
     90 end;
     91 
     92 procedure TForm1.btn2Click(Sender: TObject);
     93 var
     94   ID:DWORD;
     95 begin
     96   MyThread:=TMyThread.Create(False);      {创建线程}
     97 end;
     98 
     99 procedure TForm1.btn3Click(Sender: TObject);
    100 begin
    101   MyEvent.SetEvent;    {启动}  {事件类没有PulseEvent启动一次后轻描谈写}
    102 end;
    103 
    104 procedure TForm1.btn4Click(Sender: TObject);
    105 begin
    106   MyEvent.ResetEvent;  {暂停}
    107 end;
    108 
    109 procedure TForm1.FormCreate(Sender: TObject);
    110 begin
    111    btn1.Caption:='创建事件';
    112    btn2.Caption:='创建线程';
    113    btn3.Caption:='启动';
    114    btn4.Caption:='暂停';
    115 end;
    116 
    117 procedure TForm1.FormDestroy(Sender: TObject);
    118 begin
    119   MyEvent.Free;        {释放}
    120 end;
    121 
    122 end.

    总结:

    多线程用TThread类以及Uses syncobjs后使用的 TCriticalSection (临界区),TMutex(互斥体),TSemaphore (信号对象,D2009才开始有),TEvent (事件对象)很多都是引用了API的方法进行了一定的简化,不过也有部分功能的缺失,如Event (事件对象)缺少了启动步进一次后暂停的功能,不过基本在同步上已经够用了,另外在TThread类声明的Execute过程里,加上FreeOnTerminate := True;这句会让线程执行完后自动释放,还可以把功能代码的方法套在Synchronize()里,用于同步一些非线程安全的控件对象,避免多个线程同时对一个对象操作引发的问题。

  • 相关阅读:
    数组元素的查找1
    排序——选择排序
    排序——冒泡排序
    内部类——匿名内部类
    跳一跳
    数组元素换位置游戏
    六 java和Tomcat
    九 Jenkins持续集成
    八 ip和子网详解
    七 Git版本控制
  • 原文地址:https://www.cnblogs.com/chaosc/p/5819178.html
Copyright © 2020-2023  润新知