Este exemplo mostra como implementar um mecanismo de pausa e reinício, bem como uma forma de fazer uma thread esperar um tempo antes de continuar sua execução cíclica (timeout)

Formato
Delphi
Post date
2021-09-25 03:50
Publication Period
Unlimited
  1. program SuperThread;
  2. {$APPTYPE CONSOLE}
  3. {$R *.res}
  4. uses
  5. System.SysUtils, System.SyncObjs, System.Classes;
  6. type
  7. TMinhaThread = class (TThread)
  8. private
  9. FPauseRestart: TEvent;
  10. FTimeOut: TEvent;
  11. FTimeOutValue: Byte;
  12. protected
  13. procedure Execute; override;
  14. public
  15. constructor Create(ATimeOutValue: Byte); reintroduce;
  16. destructor Destroy; override;
  17. procedure Pause;
  18. procedure Restart;
  19. end;
  20. { TMinhaThread }
  21. constructor TMinhaThread.Create(ATimeOutValue: Byte);
  22. begin
  23. inherited Create(True);
  24. FPauseRestart := nil;
  25. FTimeOut := nil;
  26. FTimeOutValue := ATimeOutValue;
  27. end;
  28. destructor TMinhaThread.Destroy;
  29. begin
  30. // Configura a propriedade Terminated como True fazendo com que os pontos de
  31. // verificação normais do loop da thread a façam terminar "graciosamente"
  32. Terminate;
  33. // Caso a thread esteja parada no seu timeout, faz com que a função WaitFor
  34. // retorne, o que faz a thread continuar sua execução. Como o WaitFor de
  35. // timeout é o último comando do loop da thread, a próxima linha a ser
  36. // executada é a condição do loop da thread (not Terminated). Como já
  37. // configuramos Terminated como true, o loop termina e o método execute da
  38. // thread também. Adicionalmente, o bloco abaixo libera FTimeOut da memória
  39. if Assigned(FTimeOut) then
  40. begin
  41. FTimeOut.SetEvent;
  42. FTimeOut.Free;
  43. end;
  44. // Caso a thread esteja pausada, faz com que a função WaitFor retorne, o que
  45. // faz a thread continuar sua execução. Como o WaitFor de pausa é o primeiro
  46. // comando do loop da thread, a próxima linha a ser executada é a verificação
  47. // adicional (dentro do loop) para saber se a thread não foi terminada. Como
  48. // já configuramos Terminated como true, o bloco de instruções úteis da thread
  49. // não será executado e o fluxo de execução volta para a condição do loop (not
  50. // Terminated), que retorna False novamente e termina o loop e
  51. // consequentemente o método execute. Adicionalmente, o bloco abaixo libera
  52. // FPauseRestart da memória
  53. if Assigned(FPauseRestart) then
  54. begin
  55. FPauseRestart.SetEvent;
  56. FPauseRestart.Free;
  57. end;
  58. inherited;
  59. end;
  60. procedure TMinhaThread.Execute;
  61. var
  62. WR: TWaitResult;
  63. begin
  64. // Este TEvent serve apenas para pausar e reiniciar a thread. Enquanto a
  65. // thread está no estado de não pausada, o while mais adiante, fica rodando
  66. // indefinidamente enquanto a thread não estiver terminada. Quando a thread é
  67. // pausada, o fluxo fica parado na linha do WaitFor indefinidamente, sem
  68. // consumir recursos e a única forma de sair desse estado é despausando a
  69. // thread, que em termos práticos significa "assinalar" o evento, usando o
  70. // método SetEvent. Um evento "assinalado" é o mesmo que um evento que ocorre,
  71. // portanto, ao assinalar um evento, o método WaitFor é terminado e o retorno
  72. // é wrSignaled. Enquanto o evento não for novamente pausado (ResetEvent), ele
  73. // se mantém assinalado e por isso a linha do WaitFor retorna imediatamente
  74. // com um valor de retorno = wrSignaled. Este comportamento só é obtido porque
  75. // o segundo parâmetro do construtor do TEvent, indica que ele é ressetado
  76. // manualmente. Se este parâmetro indicasse que ele é ressetado
  77. // automaticamente, o evento seria "desassinalado" imediatamente após ele ter
  78. // sido "assinalado", isto é, chamadas subsequentes a WaitFor iriam ficar
  79. // "travadas" até que o evento fosse assinalado novamente
  80. FPauseRestart := TEvent.Create(nil,True,True,'Pause/Restart');
  81. // --- ---- ---- -----
  82. // | | | |
  83. // | | | \......> Nome único para a instância, do contrário, será usado o já existente
  84. // | | \............> Podemos já criar SINALIZADO (no caso isso significa que a thread não estará pausada inicialmente)
  85. // | \.................> Indica se será resetado MANUALMENTE ou AUTOMATICAMENTE
  86. // \......................> Atributos, nil basta na maioria das necessidades
  87. // Este TEvent serve para que a tread fique aguardando por um determinado
  88. // período de tempo antes de continuar o seu loop e ainda permite que a
  89. // qualquer momento esta "pausa temporizada" seja interrompida a fim de
  90. // permitir que a thread seja finalizada "graciosamente"
  91. FTimeOut := TEvent.Create(nil,False,False,'TimeOut');
  92. while not Terminated do
  93. begin
  94. WR := FPauseRestart.WaitFor(INFINITE);
  95. // Após sair da pausa, é necessário verificar se a thread ainda precisa ser
  96. // executada
  97. if not Terminated then
  98. case WR of
  99. // A única forma válida de saída do estado de pausa que permite que o
  100. // código da thread seja executado é se ela foi explicitamente
  101. // despausada, o que implica WR = wrSignaled. Em qualquer outro caso, o
  102. // código da thread não deve ser executado
  103. wrSignaled: begin
  104. { ================================================================== }
  105. { AQUI VAI O SEU CÓDIGO ÚTIL, ISTO É, AQUILO QUE DEVE SER EXECUTADO }
  106. { POR ESTA THREAD EM SEGUNDO PLANO }
  107. { ================================================================== }
  108. FTimeOut.WaitFor(FTimeOutValue * 1000);
  109. end;
  110. end;
  111. end;
  112. end;
  113. procedure TMinhaThread.Pause;
  114. begin
  115. if Started and Assigned(FPauseRestart) then
  116. FPauseRestart.ResetEvent;
  117. end;
  118. procedure TMinhaThread.Restart;
  119. begin
  120. if Started and Assigned(FPauseRestart) then
  121. FPauseRestart.SetEvent;
  122. end;
  123. var
  124. MinhaThread: TMinhaThread;
  125. begin
  126. try
  127. // Exte exemplo funciona corretamente com threads que não são
  128. // FreeOnTerminate. É necessário destruir a instância da thread, a qual vai
  129. // executar o seu destrutor interno e parar o funcionamento da mesma de
  130. // forma ordenada
  131. MinhaThread := TMinhaThread.Create(60); // 60 segundos
  132. MinhaThread.Start;
  133. Sleep(5000);
  134. MinhaThread.Pause;
  135. Sleep(5000);
  136. MinhaThread.Restart;
  137. Sleep(5000);
  138. MinhaThread.Free;
  139. except
  140. on E: Exception do
  141. Writeln(E.ClassName, ': ', E.Message);
  142. end;
  143. end.
Download Printable view

URL of this paste

Embed with JavaScript

Embed with iframe

Raw text