之前學習了用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()里,用於同步一些非線程安全的控件對象,避免多個線程同時對一個對象操作引發的問題。

