source: trunk/Packages/Common/UResetableThread.pas

Last change on this file was 11, checked in by chronos, 11 years ago
File size: 6.1 KB
Line 
1unit UResetableThread;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, syncobjs, UThreading, UPool;
9
10type
11 TResetableThread = class;
12
13 { TResetableThreadExecute }
14
15 TResetableThreadExecute = class(TTermThread)
16 Parent: TResetableThread;
17 procedure Execute; override;
18 end;
19
20 { TResetableThread }
21
22 TResetableThread = class
23 private
24 FLock: TCriticalSection;
25 FOnException: TExceptionEvent;
26 FOnFinished: TNotifyEvent;
27 FStartEvent: TEvent;
28 FStopEvent: TEvent;
29 FThread: TResetableThreadExecute;
30 FStopPending: Boolean;
31 FRunning: Boolean;
32 FRunningPending: Boolean;
33 function GetRunning: Boolean;
34 procedure WaitForStart;
35 procedure WaitForStop;
36 public
37 Method: TMethodCall;
38 procedure Stop;
39 procedure Start;
40 constructor Create;
41 destructor Destroy; override;
42 property OnFinished: TNotifyEvent read FOnFinished write FOnFinished;
43 property StopPending: Boolean read FStopPending;
44 property Running: Boolean read GetRunning;
45 property OnException: TExceptionEvent read FOnException
46 write FOnException;
47 end;
48
49 { TThreadPool }
50
51 TThreadPool = class(TThreadedPool)
52 private
53 FOnException: TExceptionEvent;
54 procedure MethodFinish(Sender: TObject);
55 protected
56 function NewItemObject: TObject; override;
57 public
58 LastExceptionClass: TClass;
59 LastExceptionMessage: string;
60 procedure ThreadException(Sender: TObject; E: Exception);
61 procedure CheckException;
62 procedure WaitForEmpty;
63 procedure Clear;
64 procedure RunInThread(AMethod: TMethodCall);
65 constructor Create; override;
66 destructor Destroy; override;
67 property OnException: TExceptionEvent read FOnException
68 write FOnException;
69 end;
70
71resourcestring
72 SWaitError = 'WaitFor error';
73
74
75implementation
76
77{ TResetableThread }
78
79function TResetableThread.GetRunning: Boolean;
80begin
81 Result := FRunning;
82end;
83
84procedure TResetableThread.Stop;
85begin
86 try
87 FLock.Acquire;
88 if FRunning then FStopPending := True;
89 finally
90 FLock.Release;
91 end;
92end;
93
94procedure TResetableThread.Start;
95begin
96 try
97 FLock.Acquire;
98 //FRunningPending := True;
99 FStartEvent.SetEvent;
100 finally
101 FLock.Release;
102 end;
103end;
104
105procedure TResetableThread.WaitForStart;
106//var
107// WaitResult: TWaitResult;
108begin
109 //try
110 // FLock.Acquire;
111// while (not FThread.Terminate) and (not FRunning) and (not FRunningPending) do
112// Sleep(1);
113 //repeat
114 //try
115 // FLock.Release;
116 //WaitResult := FStartEvent.WaitFor(1);
117 //finally
118 // FLock.Acquire;
119 //end;
120 //until (WaitResult <> wrTimeout) or FRunning or FThread.Terminated;
121 //if WaitResult = wrError then
122 // raise Exception.Create(SWaitError);
123 //finally
124 // FLock.Release;
125 //end;
126end;
127
128procedure TResetableThread.WaitForStop;
129//var
130// WaitState: TWaitResult;
131begin
132 try
133 FLock.Acquire;
134 repeat
135 try
136 FLock.Release;
137 //WaitState := FStopEvent.WaitFor(1);
138 Sleep(1);
139 finally
140 FLock.Acquire;
141 end;
142 until (not FRunning); // or (WaitState <> wrTimeout);
143 finally
144 FLock.Release;
145 end;
146end;
147
148constructor TResetableThread.Create;
149begin
150 FLock := TCriticalSection.Create;
151 FRunning := False;
152 FStopPending := False;
153 FStartEvent := TEvent.Create(nil, False, False, '');
154 FStopEvent := TEvent.Create(nil, False, False, '');
155 FThread := TResetableThreadExecute.Create(True);
156 FThread.Name := 'ResetableThread';
157 FThread.Parent := Self;
158 FThread.Resume;
159end;
160
161destructor TResetableThread.Destroy;
162begin
163 Stop;
164 WaitForStop;
165 FThread.Free; // Do not use FreeAndNil
166 FreeAndNil(FStartEvent);
167 FreeAndNil(FStopEvent);
168 FreeAndNil(FLock);
169 inherited Destroy;
170end;
171
172{ TResetableThreadExecute }
173
174procedure TResetableThreadExecute.Execute;
175var
176 WaitResult: TWaitResult;
177begin
178 while not Terminated do
179 with Parent do begin
180 try
181 FLock.Acquire;
182 //WaitForStart;
183 (*while (not Terminated) and (not FRunning) and (not FRunningPending) do
184 try
185 FLock.Release;
186 Sleep(1);
187 finally
188 FLock.Acquire;
189 end;*)
190 repeat
191 try
192 FLock.Release;
193 WaitResult := FStartEvent.WaitFor(1);
194 finally
195 FLock.Acquire;
196 end;
197 until (WaitResult <> wrTimeout) or Terminated;
198
199 if not Terminated then begin
200 //try
201 //FLock.Acquire;
202 FRunning := True;
203 FRunningPending := False;
204 try
205 FLock.Release;
206 try
207 try
208 Method;
209 finally
210 if Assigned(FOnFinished) then
211 FOnFinished(Parent);
212 end;
213 except
214 on E: Exception do
215 if Assigned(FOnException) then
216 FOnException(Self, E);
217 end;
218 finally
219 FLock.Acquire;
220 end;
221 FRunning := False;
222 FStopPending := False;
223 FStopEvent.SetEvent;
224 //finally
225 //FLock.Release;
226 //end;
227 end;
228 finally
229 FLock.Release;
230 end;
231 end;
232end;
233
234{ TThreadPool }
235
236procedure TThreadPool.MethodFinish(Sender: TObject);
237begin
238 Release(Sender);
239end;
240
241procedure TThreadPool.ThreadException(Sender: TObject; E: Exception);
242begin
243 LastExceptionClass := E.ClassType;
244 LastExceptionMessage := E.Message;
245end;
246
247procedure TThreadPool.CheckException;
248begin
249 if Assigned(LastExceptionClass) then
250 raise Exception.Create(LastExceptionMessage);
251end;
252
253function TThreadPool.NewItemObject: TObject;
254begin
255 Result := TResetableThread.Create;
256 TResetableThread(Result).OnException := ThreadException;
257end;
258
259procedure TThreadPool.WaitForEmpty;
260begin
261 while UsedCount > 0 do begin
262 Sleep(1);
263 end;
264end;
265
266procedure TThreadPool.Clear;
267begin
268 TotalCount := 0;
269 LastExceptionClass := nil;
270 LastExceptionMessage := '';
271end;
272
273procedure TThreadPool.RunInThread(AMethod: TMethodCall);
274begin
275 try
276 with TResetableThread(Acquire) do begin
277 Method := AMethod;
278 OnFinished := MethodFinish;
279 Start;
280 end;
281 finally
282 CheckException;
283 end;
284end;
285
286constructor TThreadPool.Create;
287begin
288 inherited Create;
289end;
290
291destructor TThreadPool.Destroy;
292begin
293 TotalCount := 0;
294 WaitForEmpty;
295 inherited Destroy;
296end;
297
298end.
299
Note: See TracBrowser for help on using the repository browser.