source: trunk/Packages/Common/UThreading.pas

Last change on this file was 207, checked in by chronos, 3 years ago
  • Modified: Updated Common package.
  • Modified: CoolTranslator package merged into Common package.
  • Fixed: Build with Lazarus 2.0.12
File size: 9.0 KB
Line 
1unit UThreading;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, Forms, fgl, 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: TThreadID; 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: TThreadID 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: TThreadID; 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(TFPGObjectList<TVirtualThread>)
105 function FindById(Id: TThreadID): 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 try
167 ThreadListLock.Acquire;
168 Thread := ThreadList.FindById(ThreadID);
169 finally
170 ThreadListLock.Release;
171 end;
172 if Assigned(Thread) then begin
173 Thread.Synchronize(Method);
174 end else raise Exception.Create(Format(SCurrentThreadNotFound, [ThreadID]));
175 end;
176end;
177
178{ TThreadList }
179
180function TThreadList.FindById(Id: TThreadID): TVirtualThread;
181var
182 I: Integer;
183begin
184 I := 0;
185 while (I < ThreadList.Count) and (ThreadList[I].ThreadID <> Id) do
186 Inc(I);
187 if I < ThreadList.Count then Result := ThreadList[I]
188 else Result := nil;
189end;
190
191constructor TThreadList.Create;
192begin
193 inherited Create;
194end;
195
196{ TListedThreadExecute }
197
198procedure TListedThreadExecute.Execute;
199begin
200 try
201 try
202 Parent.Execute;
203 except
204 on E: Exception do
205 if Assigned(OnException) then
206 OnException(Parent.FThread, E);
207 end;
208 finally
209 Parent.FFinished := True;
210 end;
211end;
212
213{ TListedThread }
214
215function TListedThread.GetFinished: Boolean;
216begin
217 Result := FFinished;
218end;
219
220function TListedThread.GetFreeOnTerminate: Boolean;
221begin
222 Result := FThread.FreeOnTerminate;
223end;
224
225function TListedThread.GetPriority: TThreadPriority;
226begin
227 Result := FThread.Priority;
228end;
229
230function TListedThread.GetSuspended: Boolean;
231begin
232 Result := FThread.Suspended;
233end;
234
235function TListedThread.GetTerminated: Boolean;
236begin
237 Result := FTerminated;
238end;
239
240function TListedThread.GetThreadId: TThreadID;
241begin
242 Result := FThread.ThreadID;
243end;
244
245procedure TListedThread.SetFreeOnTerminate(const AValue: Boolean);
246begin
247 FThread.FreeOnTerminate := AValue;
248end;
249
250procedure TListedThread.SetPriority(const AValue: TThreadPriority);
251begin
252 FThread.Priority := AValue;
253end;
254
255procedure TListedThread.SetSuspended(const AValue: Boolean);
256begin
257 FThread.Suspended := AValue;
258end;
259
260procedure TListedThread.SetTerminated(const AValue: Boolean);
261begin
262 FTerminated := AValue;
263 if AValue then FThread.Terminate;
264end;
265
266constructor TListedThread.Create(CreateSuspended: Boolean;
267 const StackSize: SizeUInt);
268begin
269 FFinished := False;
270 FTerminated := False;
271
272 FThread := TListedThreadExecute.Create(True, StackSize);
273 FThread.Parent := Self;
274 try
275 ThreadListLock.Acquire;
276 ThreadList.Add(Self);
277 finally
278 ThreadListLock.Release;
279 end;
280 if CreateSuspended = False then FThread.Start;
281end;
282
283destructor TListedThread.Destroy;
284begin
285 if not Suspended then
286 begin
287 Terminate;
288 WaitFor;
289 end;
290 try
291 ThreadListLock.Acquire;
292 ThreadList.Delete(ThreadList.IndexOf(Self));
293 finally
294 ThreadListLock.Release;
295 end;
296 FThread.Free;
297 inherited Destroy;
298end;
299
300procedure TListedThread.Sleep(Delay: Integer);
301const
302 Quantum = 20;
303var
304 I: Integer;
305begin
306 if Terminated then Exit;
307 SysUtils.Sleep(Delay mod Quantum);
308 for I := 1 to (Delay div Quantum) do begin
309 if Terminated then Break;
310 SysUtils.Sleep(Quantum);
311 end;
312end;
313
314procedure TListedThread.Execute;
315begin
316end;
317
318procedure TListedThread.Start;
319begin
320 FThread.Start;
321end;
322
323procedure TListedThread.Terminate;
324begin
325 FTerminated := True;
326 FThread.Terminate;
327end;
328
329procedure TListedThread.Synchronize(AMethod: TThreadMethod);
330begin
331 FThread.Synchronize(FThread, AMethod);
332end;
333
334procedure TListedThread.WaitFor;
335begin
336 FThread.WaitFor;
337end;
338
339{ TTermThread }
340
341procedure TTermThread.Execute;
342begin
343 try
344 State := ttsRunning;
345 Method;
346 State := ttsFinished;
347 if Assigned(FOnFinished) then
348 FOnFinished(Self);
349 except
350 on E: Exception do begin
351 ExceptionMessage := E.Message;
352 State := ttsExceptionOccured;
353 if Assigned(OnException) then
354 OnException(FThread, E);
355 end;
356 end;
357end;
358
359initialization
360
361ThreadListLock := TCriticalSection.Create;
362ThreadList := TThreadList.Create;
363ThreadList.FreeObjects := False;
364
365finalization
366
367ThreadList.Free;
368ThreadListLock.Free;
369
370end.
371
Note: See TracBrowser for help on using the repository browser.