为什么TTimer不能在OTL工作者任务中工作?

时间:2015-07-08 12:30:01

标签: delphi delphi-xe4 omnithreadlibrary

我想在OmniThreadLibrary工作任务中实现重复任务,该任务在另一个线程中运行。例如,该任务应每3秒执行一次。 因此,我写了一个TOmniWorker后代,其实例为TTimer,如下所示:

program Project14;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Vcl.ExtCtrls,
  Vcl.Forms,
  OtlTaskControl;

type
  TMyTimerWorker = class(TOmniWorker)
  strict private
    FTimer: TTimer;
    procedure DoOnTimer(Sender: TObject);
  protected
    function Initialize: Boolean; override;
    procedure Cleanup; override;
  end;

{ TMyTimerWorker }

procedure TMyTimerWorker.Cleanup;
begin
  FTimer.Free;
  inherited;
end;

procedure TMyTimerWorker.DoOnTimer(Sender: TObject);
begin
  Beep;
end;

function TMyTimerWorker.Initialize: Boolean;
begin
  Result := inherited;
  if not Result then exit;

  FTimer := TTimer.Create(nil);
  FTimer.OnTimer  := DoOnTimer;
  FTimer.Interval := 3000;
  FTimer.Enabled  := True; // note: this isn't necessary, but is added to avoid hints that 'Enabled' might be 'False'
end;

var
  LTimerWorker: IOmniWorker;
begin
  try
    LTimerWorker := TMyTimerWorker.Create;
    CreateTask(LTimerWorker).Unobserved.Run;
    while True do
      Application.ProcessMessages;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

我在InitializeDoOnTimer中设置了断点。前者执行得很好但后者根本不会被调用。顺便说一句:Cleanup也没有被调用,所以任务仍在运行。

我做错了什么?是否无法在OTL任务中使用TTimer?如果是,为什么?

更新:我找到了TTimer({}的workaround,但为什么TTimer接近不起作用?

1 个答案:

答案 0 :(得分:3)

You TTimer-based code doesn't work because TTimer uses windows messages to trigger the timer event and windows messages are not processed in an OTL worker by default.

Call .MsgWait before .Run and internal worker loop will use MsgWaitForMultipleObjects instead of WaitForMultipleObjects which will allow for message processing.

Saying that, you really should not use TTimer in background tasks because - as others have said - TTimer is not threadsafe.