source: trunk/Packages/Common/ResetableThread.pas

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