Как реализовать поток, который периодически что-то проверяет, используя минимальные ресурсы? - PullRequest
13 голосов
/ 07 декабря 2011

Я хотел бы иметь поток, работающий в фоновом режиме, который будет проверять соединение с каким-либо сервером с заданным интервалом времени.Например, каждые 5 секунд.

Я не знаю, есть ли хороший «шаблон дизайна» для этого?Если я правильно помню, я где-то читал, что спящий поток в методе execute не годится.Но я могу ошибаться.

Кроме того, я мог бы использовать обычный класс TThread или библиотеку потоков OTL.

Есть идеи?

Спасибо.

Ответы [ 5 ]

16 голосов
/ 07 декабря 2011

В OmniThreadLibrary , вы должны сделать:

uses
  OtlTask,
  OtlTaskControl;

type
  TTimedTask = class(TOmniWorker)
  public
    procedure Timer1;
  end;

var
  FTask: IOmniTaskControl;

procedure StartTaskClick;
begin
  FTask := CreateTask(TTimedTask.Create())
    .SetTimer(1, 5*1000, @TTimedTask.Timer1)
    .Run;
end;

procedure StopTaskClick;
begin
  FTask.Terminate;
  FTask := nil;
end;

procedure TTimedTask.Timer1;
begin
  // this is triggered every 5 seconds
end;

Что касается сна в Execute - это зависит от того, как вы это делаете. Если вы используете Sleep, то это может быть не очень разумно (например, потому что это предотвратит остановку потока во время сна). Спать с WaitForSingleObject нормально.

Пример TThread и WaitForSingleObject:

type
  TTimedThread = class(TThread)
  public
    procedure Execute; override;
  end;

var
  FStopThread: THandle;
  FThread: TTimedThread;

procedure StartTaskClick(Sender: TObject);
begin
  FStopThread := CreateEvent(nil, false, false, nil);
  FThread := TTimedThread.Create;
end;

procedure StopTaskClick(Sender: TObject);
begin
  SetEvent(FStopThread);
  FThread.Terminate;
  FThread.Free;
  CloseHandle(FStopThread);
end;

{ TTimedThread }

procedure TTimedThread.Execute;
begin
  while WaitForSingleObject(Form71.FStopThread, 5*1000) = WAIT_TIMEOUT do begin
    // this is triggered every 5 seconds
  end;
end;

Реализация таймера OTL аналогична приведенному выше коду TThread. Таймеры OTL хранятся в списке приоритетов (в основном таймеры сортируются по времени «следующего появления»), а внутренний диспетчер MsgWaitForMultipleObjects в TOmniWorker указывает соответствующее значение тайм-аута для таймера с самым высоким приоритетом.

14 голосов
/ 07 декабря 2011

Вы можете использовать событие и реализовать метод Execute потомка TThread с помощью цикла с WaitForSingleObject ожиданием события с указанием времени ожидания. Таким образом, вы можете разбудить нить немедленно, когда это необходимо, например, при завершении.

1 голос
/ 07 декабря 2011

Чтобы добавить еще одно средство для достижения 5-секундного события, можно использовать мультимедийный таймер, который похож на TTimer, но не зависит от вашего приложения.После настройки (вы можете настроить однократный или повторяющийся) он перезвонит вам в другой поток.По своей природе это очень точно (с точностью до 1 мс).Посмотрите пример кода Delphi здесь .

Код для вызова таймера прост и поддерживается на всех платформах Windows.

1 голос
/ 07 декабря 2011

Если поток работает в течение всего срока службы приложения, он может быть просто остановлен операционной системой при закрытии приложения и не требует точного времени, зачем прибегать к решениям, требующим больше ввода данных, чем в режиме сна (5000)?

0 голосов
/ 07 декабря 2011

Использование CreateWaitableTimer и SetWaitableTimer

...