source: trunk/Packages/Common/UThreading.pas

Last change on this file was 41, checked in by chronos, 6 years ago
  • Modified: Build under Lazarus 2.0.
  • Modified: Used .lrj files instead of .lrt files.
  • Modified: Removed TemplateGenerics package.
File size: 8.9 KB
Line 
1unit UThreading;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, Forms, Contnrs, SyncObjs;
9
10type
11 TExceptionEvent = procedure (Sender: TObject; E: Exception) of object;
12 TMethodCall = procedure of object;
13
14
15 { TVirtualThread }
16
17 TVirtualThread = class
18 private
19 function GetFinished: Boolean; virtual; abstract;
20 function GetFreeOnTerminate: Boolean; virtual; abstract;
21 function GetPriority: TThreadPriority; virtual; abstract;
22 function GetSuspended: Boolean; virtual; abstract;
23 function GetTerminated: Boolean; virtual; abstract;
24 function GetThreadId: Integer; virtual; abstract;
25 procedure SetFreeOnTerminate(const AValue: Boolean); virtual; abstract;
26 procedure SetPriority(const AValue: TThreadPriority); virtual; abstract;
27 procedure SetSuspended(const AValue: Boolean); virtual; abstract;
28 procedure SetTerminated(const AValue: Boolean); virtual; abstract;
29 public
30 Name: string;
31 procedure Execute; virtual; abstract;
32 procedure Start; virtual; abstract;
33 procedure Terminate; virtual; abstract;
34 procedure Synchronize(AMethod: TThreadMethod); virtual; abstract;
35 procedure WaitFor; virtual; abstract;
36 procedure Sleep(Delay: Integer); virtual; abstract;
37 property FreeOnTerminate: Boolean read GetFreeOnTerminate
38 write SetFreeOnTerminate;
39 property Suspended: Boolean read GetSuspended
40 write SetSuspended;
41 property Priority: TThreadPriority read GetPriority write SetPriority;
42 property Terminated: Boolean read GetTerminated write SetTerminated;
43 property Finished: Boolean read GetFinished;
44 property ThreadId: Integer read GetThreadId;
45 end;
46
47 TVirtualThreadClass = class of TVirtualThread;
48
49 TListedThread = class;
50
51 { TListedThreadExecute }
52
53 TListedThreadExecute = class(TThread)
54 Parent: TListedThread;
55 procedure Execute; override;
56 end;
57
58 { TListedThread }
59
60 TListedThread = class(TVirtualThread)
61 private
62 FTerminated: Boolean;
63 FFinished: Boolean;
64 FThread: TListedThreadExecute;
65 function GetFinished: Boolean; override;
66 function GetFreeOnTerminate: Boolean; override;
67 function GetPriority: TThreadPriority; override;
68 function GetSuspended: Boolean; override;
69 function GetTerminated: Boolean; override;
70 function GetThreadId: Integer; override;
71 procedure SetFreeOnTerminate(const AValue: Boolean); override;
72 procedure SetPriority(const AValue: TThreadPriority); override;
73 procedure SetSuspended(const AValue: Boolean); override;
74 procedure SetTerminated(const AValue: Boolean); override;
75 public
76 constructor Create(CreateSuspended: Boolean;
77 const StackSize: SizeUInt = DefaultStackSize);
78 destructor Destroy; override;
79 procedure Sleep(Delay: Integer); override;
80 procedure Execute; override;
81 procedure Start; override;
82 procedure Terminate; override;
83 procedure Synchronize(AMethod: TThreadMethod); override;
84 procedure WaitFor; override;
85 end;
86
87 TTermThreadState = (ttsReady, ttsRunning, ttsFinished, ttsExceptionOccured);
88
89 { TTermThread }
90
91 TTermThread = class(TListedThread)
92 private
93 FOnFinished: TNotifyEvent;
94 public
95 State: TTermThreadState;
96 ExceptionMessage: string;
97 Method: TMethodCall;
98 procedure Execute; override;
99 property OnFinished: TNotifyEvent read FOnFinished write FOnFinished;
100 end;
101
102 { TThreadList }
103
104 TThreadList = class(TObjectList)
105 function FindById(Id: Integer): TVirtualThread;
106 constructor Create; virtual;
107 end;
108
109var
110 ThreadList: TThreadList;
111 ThreadListLock: TCriticalSection;
112 OnException: TExceptionEvent;
113
114procedure RunInThread(Method: TMethodCall);
115procedure RunInThreadAsync(Method: TMethodCall; Callback: TNotifyEvent = nil);
116procedure Synchronize(Method: TMethodCall);
117
118resourcestring
119 SCurrentThreadNotFound = 'Current thread ID %d not found in virtual thread list.';
120
121
122implementation
123
124procedure RunInThread(Method: TMethodCall);
125var
126 Thread: TTermThread;
127begin
128 try
129 Thread := TTermThread.Create(True);
130 Thread.FreeOnTerminate := False;
131 Thread.Method := Method;
132 Thread.Start;
133 while (Thread.State = ttsRunning) or (Thread.State = ttsReady) do begin
134 if MainThreadID = ThreadID then Application.ProcessMessages;
135 Sleep(1);
136 end;
137 if Thread.State = ttsExceptionOccured then
138 raise Exception.Create(Thread.ExceptionMessage);
139 finally
140 Thread.Free;
141 end;
142end;
143
144procedure RunInThreadAsync(Method: TMethodCall; Callback: TNotifyEvent = nil);
145var
146 Thread: TTermThread;
147begin
148 try
149 Thread := TTermThread.Create(True);
150 Thread.FreeOnTerminate := True;
151 Thread.Method := Method;
152 Thread.OnFinished := CallBack;
153 Thread.Start;
154 //if Thread.State = ttsExceptionOccured then
155 // raise Exception.Create(Thread.ExceptionMessage);
156 finally
157 end;
158end;
159
160procedure Synchronize(Method: TMethodCall);
161var
162 Thread: TVirtualThread;
163begin
164 if MainThreadID = ThreadID then Method
165 else begin
166 Thread := ThreadList.FindById(ThreadID);
167 if Assigned(Thread) then begin
168 Thread.Synchronize(Method);
169 end else raise Exception.Create(Format(SCurrentThreadNotFound, [ThreadID]));
170 end;
171end;
172
173{ TThreadList }
174
175function TThreadList.FindById(Id: Integer): TVirtualThread;
176var
177 I: Integer;
178begin
179 I := 0;
180 while (I < ThreadList.Count) and (TVirtualThread(ThreadList[I]).ThreadID <> Id) do
181 Inc(I);
182 if I < ThreadList.Count then Result := TVirtualThread(ThreadList[I])
183 else Result := nil;
184end;
185
186constructor TThreadList.Create;
187begin
188 inherited Create;
189end;
190
191{ TListedThreadExecute }
192
193procedure TListedThreadExecute.Execute;
194begin
195 try
196 try
197 Parent.Execute;
198 except
199 on E: Exception do
200 if Assigned(OnException) then
201 OnException(Parent.FThread, E);
202 end;
203 finally
204 Parent.FFinished := True;
205 end;
206end;
207
208{ TListedThread }
209
210function TListedThread.GetFinished: Boolean;
211begin
212 Result := FFinished;
213end;
214
215function TListedThread.GetFreeOnTerminate: Boolean;
216begin
217 Result := FThread.FreeOnTerminate;
218end;
219
220function TListedThread.GetPriority: TThreadPriority;
221begin
222 Result := FThread.Priority;
223end;
224
225function TListedThread.GetSuspended: Boolean;
226begin
227 Result := FThread.Suspended;
228end;
229
230function TListedThread.GetTerminated: Boolean;
231begin
232 Result := FTerminated;
233end;
234
235function TListedThread.GetThreadId: Integer;
236begin
237 Result := FThread.ThreadID;
238end;
239
240procedure TListedThread.SetFreeOnTerminate(const AValue: Boolean);
241begin
242 FThread.FreeOnTerminate := AValue;
243end;
244
245procedure TListedThread.SetPriority(const AValue: TThreadPriority);
246begin
247 FThread.Priority := AValue;
248end;
249
250procedure TListedThread.SetSuspended(const AValue: Boolean);
251begin
252 FThread.Suspended := AValue;
253end;
254
255procedure TListedThread.SetTerminated(const AValue: Boolean);
256begin
257 FTerminated := AValue;
258 if AValue then FThread.Terminate;
259end;
260
261constructor TListedThread.Create(CreateSuspended: Boolean;
262 const StackSize: SizeUInt);
263begin
264 FFinished := False;
265 FTerminated := False;
266
267 FThread := TListedThreadExecute.Create(True, StackSize);
268 FThread.Parent := Self;
269 try
270 ThreadListLock.Acquire;
271 ThreadList.Add(Self);
272 finally
273 ThreadListLock.Release;
274 end;
275 if CreateSuspended = False then FThread.Start;
276end;
277
278destructor TListedThread.Destroy;
279begin
280 if not Suspended then
281 begin
282 Terminate;
283 WaitFor;
284 end;
285 try
286 ThreadListLock.Acquire;
287 ThreadList.Delete(ThreadList.IndexOf(Self));
288 finally
289 ThreadListLock.Release;
290 end;
291 FThread.Free;
292 inherited Destroy;
293end;
294
295procedure TListedThread.Sleep(Delay: Integer);
296const
297 Quantum = 20;
298var
299 I: Integer;
300begin
301 if Terminated then Exit;
302 SysUtils.Sleep(Delay mod Quantum);
303 for I := 1 to (Delay div Quantum) do begin
304 if Terminated then Break;
305 SysUtils.Sleep(Quantum);
306 end;
307end;
308
309procedure TListedThread.Execute;
310begin
311end;
312
313procedure TListedThread.Start;
314begin
315 FThread.Start;
316end;
317
318procedure TListedThread.Terminate;
319begin
320 FTerminated := True;
321 FThread.Terminate;
322end;
323
324procedure TListedThread.Synchronize(AMethod: TThreadMethod);
325begin
326 FThread.Synchronize(FThread, AMethod);
327end;
328
329procedure TListedThread.WaitFor;
330begin
331 FThread.WaitFor;
332end;
333
334{ TTermThread }
335
336procedure TTermThread.Execute;
337begin
338 try
339 State := ttsRunning;
340 Method;
341 State := ttsFinished;
342 if Assigned(FOnFinished) then
343 FOnFinished(Self);
344 except
345 on E: Exception do begin
346 ExceptionMessage := E.Message;
347 State := ttsExceptionOccured;
348 if Assigned(OnException) then
349 OnException(FThread, E);
350 end;
351 end;
352end;
353
354initialization
355
356ThreadListLock := TCriticalSection.Create;
357ThreadList := TThreadList.Create;
358ThreadList.OwnsObjects := False;
359
360finalization
361
362ThreadList.Free;
363ThreadListLock.Free;
364
365end.
366
Note: See TracBrowser for help on using the repository browser.