tthread.inc 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. { Thread management routines }
  2. const
  3. CM_EXECPROC = $8FFF;
  4. CM_DESTROYWINDOW = $8FFE;
  5. type
  6. PRaiseFrame = ^TRaiseFrame;
  7. TRaiseFrame = record
  8. NextRaise: PRaiseFrame;
  9. ExceptAddr: Pointer;
  10. ExceptObject: TObject;
  11. ExceptionRecord: pointer; {PExceptionRecord}
  12. end;
  13. var
  14. ThreadWindow: HWND;
  15. ThreadCount: Integer;
  16. function ThreadWndProc(Window: HWnd; AMessage:UInt; WParam : WParam; LParam: LParam): Longint; stdcall;
  17. begin
  18. case AMessage of
  19. CM_EXECPROC:
  20. with TThread(lParam) do
  21. begin
  22. Result := 0;
  23. try
  24. FSynchronizeException := nil;
  25. FMethod;
  26. except
  27. { if RaiseList <> nil then
  28. begin
  29. FSynchronizeException := PRaiseFrame(RaiseList)^.ExceptObject;
  30. PRaiseFrame(RaiseList)^.ExceptObject := nil;
  31. end; }
  32. end;
  33. end;
  34. CM_DESTROYWINDOW:
  35. begin
  36. DestroyWindow(Window);
  37. Result := 0;
  38. end;
  39. else
  40. Result := DefWindowProc(Window, AMessage, wParam, lParam);
  41. end;
  42. end;
  43. const
  44. ThreadWindowClass: TWndClass = (
  45. style: 0;
  46. lpfnWndProc: nil;
  47. cbClsExtra: 0;
  48. cbWndExtra: 0;
  49. hInstance: 0;
  50. hIcon: 0;
  51. hCursor: 0;
  52. hbrBackground: 0;
  53. lpszMenuName: nil;
  54. lpszClassName: 'TThreadWindow');
  55. procedure AddThread;
  56. function AllocateWindow: HWND;
  57. var
  58. TempClass: TWndClass;
  59. ClassRegistered: Boolean;
  60. begin
  61. ThreadWindowClass.hInstance := HInstance;
  62. ThreadWindowClass.lpfnWndProc:=WndProc(@ThreadWndProc);
  63. ClassRegistered := GetClassInfo(HInstance, ThreadWindowClass.lpszClassName,
  64. @TempClass);
  65. if not ClassRegistered or (TempClass.lpfnWndProc <> WndProc(@ThreadWndProc)) then
  66. begin
  67. if ClassRegistered then
  68. Windows.UnregisterClass(ThreadWindowClass.lpszClassName, HInstance);
  69. Windows.RegisterClass(ThreadWindowClass);
  70. end;
  71. Result := CreateWindow(ThreadWindowClass.lpszClassName, '', 0,
  72. 0, 0, 0, 0, 0, 0, HInstance, nil);
  73. end;
  74. begin
  75. if ThreadCount = 0 then
  76. ThreadWindow := AllocateWindow;
  77. Inc(ThreadCount);
  78. end;
  79. procedure RemoveThread;
  80. begin
  81. Dec(ThreadCount);
  82. if ThreadCount = 0 then
  83. PostMessage(ThreadWindow, CM_DESTROYWINDOW, 0, 0);
  84. end;
  85. { TThread }
  86. function ThreadProc(Thread: TThread): Integer;
  87. var
  88. FreeThread: Boolean;
  89. begin
  90. try
  91. Thread.Execute;
  92. except
  93. Thread.FFatalException := TObject(AcquireExceptionObject);
  94. end;
  95. FreeThread := Thread.FFreeOnTerminate;
  96. Result := Thread.FReturnValue;
  97. Thread.FFinished := True;
  98. Thread.DoTerminate;
  99. if FreeThread then Thread.Free;
  100. ExitThread(Result);
  101. end;
  102. constructor TThread.Create(CreateSuspended: Boolean);
  103. var
  104. Flags: Integer;
  105. begin
  106. inherited Create;
  107. AddThread;
  108. FSuspended := CreateSuspended;
  109. Flags := 0;
  110. if CreateSuspended then Flags := CREATE_SUSPENDED;
  111. IsMultiThread := TRUE;
  112. FHandle := CreateThread(nil, 0, @ThreadProc, Pointer(self), Flags, DWord(FThreadID));
  113. FFatalException := nil;
  114. end;
  115. destructor TThread.Destroy;
  116. begin
  117. if not FFinished and not Suspended then
  118. begin
  119. Terminate;
  120. WaitFor;
  121. end;
  122. if FHandle <> 0 then CloseHandle(FHandle);
  123. FFatalException.Free;
  124. FFatalException := nil;
  125. inherited Destroy;
  126. RemoveThread;
  127. end;
  128. procedure TThread.CallOnTerminate;
  129. begin
  130. FOnTerminate(Self);
  131. end;
  132. procedure TThread.DoTerminate;
  133. begin
  134. if Assigned(FOnTerminate) then
  135. Synchronize(@CallOnTerminate);
  136. end;
  137. const
  138. Priorities: array [TThreadPriority] of Integer =
  139. (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
  140. THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
  141. THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL);
  142. function TThread.GetPriority: TThreadPriority;
  143. var
  144. P: Integer;
  145. I: TThreadPriority;
  146. begin
  147. P := GetThreadPriority(FHandle);
  148. Result := tpNormal;
  149. for I := Low(TThreadPriority) to High(TThreadPriority) do
  150. if Priorities[I] = P then Result := I;
  151. end;
  152. procedure TThread.SetPriority(Value: TThreadPriority);
  153. begin
  154. SetThreadPriority(FHandle, Priorities[Value]);
  155. end;
  156. procedure TThread.Synchronize(Method: TThreadMethod);
  157. begin
  158. FSynchronizeException := nil;
  159. FMethod := Method;
  160. SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
  161. if Assigned(FSynchronizeException) then raise FSynchronizeException;
  162. end;
  163. procedure TThread.SetSuspended(Value: Boolean);
  164. begin
  165. if Value <> FSuspended then
  166. if Value then
  167. Suspend else
  168. Resume;
  169. end;
  170. procedure TThread.Suspend;
  171. begin
  172. FSuspended := True;
  173. SuspendThread(FHandle);
  174. end;
  175. procedure TThread.Resume;
  176. begin
  177. if ResumeThread(FHandle) = 1 then FSuspended := False;
  178. end;
  179. procedure TThread.Terminate;
  180. begin
  181. FTerminated := True;
  182. end;
  183. function TThread.WaitFor: Integer;
  184. var
  185. Msg: TMsg;
  186. begin
  187. if GetCurrentThreadID = MainThreadID then
  188. while MsgWaitForMultipleObjects(1, FHandle, False, INFINITE, QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do
  189. PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE)
  190. else
  191. WaitForSingleObject(ulong(FHandle), INFINITE);
  192. GetExitCodeThread(FHandle, DWord(Result));
  193. end;
  194. {
  195. $Log$
  196. Revision 1.1 2003-10-06 21:01:07 peter
  197. * moved classes unit to rtl
  198. Revision 1.8 2003/10/06 17:06:55 florian
  199. * applied Johannes Berg's patch for exception handling in threads
  200. Revision 1.7 2003/04/23 11:35:30 peter
  201. * wndproc definition fix
  202. Revision 1.6 2002/09/07 15:15:29 peter
  203. * old logs removed and tabs fixed
  204. }