DQueueTask.pas 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. unit DQueueTask;
  2. interface
  3. uses
  4. BaseQueue, Classes,
  5. {$IFDEF MSWINDOWS} Windows, Messages, {$ENDIF}
  6. SyncObjs;
  7. type
  8. TDTaskWorker = class;
  9. TDQueueTaskConsole = class;
  10. TDataNotifyEvent = procedure(pvTaskConsole: TDQueueTaskConsole; pvData: Pointer)
  11. of object;
  12. TDQueueTaskConsole = class(TObject)
  13. private
  14. FLocker:TCriticalSection;
  15. FWorker: TDTaskWorker;
  16. FDebugInfo: String;
  17. FDataQueue: TBaseQueue;
  18. FEnable: Boolean;
  19. FOnExecute: TDataNotifyEvent;
  20. FWorkerAlive: Boolean;
  21. FCommEvent: TEvent;
  22. procedure NotifyDestroyWorker;
  23. protected
  24. procedure CheckForWorker;
  25. procedure DoTask(pvData: Pointer); virtual;
  26. public
  27. constructor Create;
  28. destructor Destroy; override;
  29. procedure PostATask(pvData:Pointer);
  30. procedure DisableWork;
  31. procedure EnableWork;
  32. function StopWorker(pvTimeOut: Cardinal): Boolean;
  33. property CommEvent: TEvent read FCommEvent;
  34. property Enable: Boolean read FEnable;
  35. property DataQueue: TBaseQueue read FDataQueue;
  36. property OnExecute: TDataNotifyEvent read FOnExecute write FOnExecute;
  37. end;
  38. TDTaskWorker = class(TThread)
  39. private
  40. FOwner: TDQueueTaskConsole;
  41. FNotify: TEvent;
  42. public
  43. constructor Create(AOwner: TDQueueTaskConsole);
  44. destructor Destroy; override;
  45. procedure Execute; override;
  46. end;
  47. var
  48. queueTaskConsole:TDQueueTaskConsole;
  49. implementation
  50. function tick_diff(tick_start, tick_end: Cardinal): Cardinal;
  51. begin
  52. if tick_end >= tick_start then
  53. result := tick_end - tick_start
  54. else
  55. result := High(Cardinal) - tick_start + tick_end;
  56. end;
  57. function CheckThreadIsAlive(const AThread: TThread): Boolean;
  58. var
  59. lvCode:Cardinal;
  60. begin
  61. Result := false;
  62. if (AThread <> nil) and (GetExitCodeThread(AThread.Handle, lvCode)) then
  63. begin
  64. if lvCode=STILL_ACTIVE then
  65. begin
  66. Result := true;
  67. end;
  68. end;
  69. end;
  70. constructor TDQueueTaskConsole.Create;
  71. begin
  72. inherited Create;
  73. FLocker := TCriticalSection.Create;
  74. FDataQueue := TBaseQueue.Create;
  75. FCommEvent := TEvent.Create(nil,false,false,'');
  76. FEnable := true;
  77. end;
  78. destructor TDQueueTaskConsole.Destroy;
  79. begin
  80. StopWorker(3000);
  81. FDataQueue.Free;
  82. FLocker.Free;
  83. FCommEvent.Free;
  84. inherited Destroy;
  85. end;
  86. procedure TDQueueTaskConsole.DoTask(pvData: Pointer);
  87. begin
  88. if Assigned(FOnExecute) then FOnExecute(Self, pvData);
  89. end;
  90. procedure TDQueueTaskConsole.CheckForWorker;
  91. begin
  92. FLocker.Enter;
  93. try
  94. if FWorker = nil then
  95. begin
  96. FWorker := TDTaskWorker.Create(Self);
  97. {$IF RTLVersion<25}
  98. FWorker.Resume;
  99. {$ELSE}
  100. FWorker.Start;
  101. {$IFEND}
  102. Sleep(10);
  103. end;
  104. if FWorker <> nil then
  105. begin
  106. FWorker.FNotify.SetEvent;
  107. end;
  108. finally
  109. FLocker.Leave;
  110. end;
  111. end;
  112. procedure TDQueueTaskConsole.NotifyDestroyWorker;
  113. begin
  114. FLocker.Enter;
  115. try
  116. FWorkerAlive := False;
  117. FWorker := nil;
  118. finally
  119. FLocker.Leave;
  120. end;
  121. end;
  122. procedure TDQueueTaskConsole.PostATask(pvData: Pointer);
  123. begin
  124. FDataQueue.Push(pvData);
  125. CheckForWorker;
  126. end;
  127. function TDQueueTaskConsole.StopWorker(pvTimeOut: Cardinal): Boolean;
  128. var
  129. l:Cardinal;
  130. begin
  131. Result := true;
  132. FEnable := false;
  133. if FWorker <> nil then
  134. begin
  135. FWorker.Terminate;
  136. FWorker.FNotify.SetEvent;
  137. FCommEvent.SetEvent;
  138. l := GetTickCount;
  139. while CheckThreadIsAlive(FWorker) do
  140. begin
  141. {$IFDEF MSWINDOWS}
  142. SwitchToThread;
  143. {$ELSE}
  144. TThread.Yield;
  145. {$ENDIF}
  146. if tick_diff(l, GetTickCount) > pvTimeOut then
  147. begin
  148. Result := false;
  149. Break;
  150. end;
  151. end;
  152. FWorker := nil;
  153. end;
  154. end;
  155. procedure TDQueueTaskConsole.DisableWork;
  156. begin
  157. FEnable := false;
  158. end;
  159. procedure TDQueueTaskConsole.EnableWork;
  160. begin
  161. FEnable := true;
  162. end;
  163. constructor TDTaskWorker.Create(AOwner: TDQueueTaskConsole);
  164. begin
  165. inherited Create(True);
  166. FreeOnTerminate := true;
  167. FNotify := TEvent.Create(nil,false,false,'');
  168. FOwner := AOwner;
  169. end;
  170. destructor TDTaskWorker.Destroy;
  171. begin
  172. FNotify.Free;
  173. inherited Destroy;
  174. end;
  175. procedure TDTaskWorker.Execute;
  176. var
  177. lvWaitResult:TWaitResult;
  178. lvData: Pointer;
  179. begin
  180. try
  181. while not self.Terminated do
  182. begin
  183. FOwner.FDebugInfo := 'Thread.Execute::FNotify.WaitFor()';
  184. lvWaitResult := FNotify.WaitFor(1000 * 30);
  185. if (lvWaitResult=wrSignaled) then
  186. begin
  187. FOwner.FDebugInfo := 'Thread.Execute::FNotify.WaitFor(), succ';
  188. while not self.Terminated do
  189. begin
  190. if not FOwner.FDataQueue.Pop(lvData) then Break;
  191. try
  192. FOwner.FDebugInfo := 'Thread.Execute::DoDataRecvdObject';
  193. FOwner.DoTask(lvData);
  194. except
  195. //FOwner.incErrorCounter;
  196. end;
  197. end;
  198. end else if lvWaitResult = wrTimeout then
  199. begin
  200. Break;
  201. end;
  202. end;
  203. finally
  204. FOwner.NotifyDestroyWorker;
  205. end;
  206. end;
  207. initialization
  208. queueTaskConsole:= TDQueueTaskConsole.Create;
  209. finalization
  210. queueTaskConsole.StopWorker(3000);
  211. queueTaskConsole.Free;
  212. queueTaskConsole := nil;
  213. end.