在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
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()里,用于同步一些非线程安全的控件对象,避免多个线程同时对一个对象操作引发的问题。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论