Как реализовать поток, который периодически что-то проверяет, используя минимальные ресурсы?
Я хотел бы иметь поток, работающий в фоновом режиме, который будет проверять подключение к некоторому серверу с заданным интервалом времени. Например, каждые 5 секунд.
Я не знаю, есть ли хороший "шаблон дизайна" для этого? Если я правильно помню, я где-то читал, что спящий поток в его методе execute не хорош. Но я могу ошибаться.
Кроме того, я мог бы использовать обычный класс TThread или библиотеку потоков OTL.
Есть идеи?
Благодарю.
5 ответов
Вы можете использовать событие и реализовать Execute
метод TThread
потомок по петле с WaitForSingleObject
ожидание события с указанием таймаута. Таким образом, вы можете разбудить поток сразу же при необходимости, например, при завершении.
В 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 указывает соответствующее значение времени ожидания для таймера с самым высоким приоритетом.
Если поток работает в течение всего жизненного цикла приложения, он может быть просто остановлен операционной системой при закрытии приложения и не требует точного хронометража, зачем беспокоиться о решениях, которые требуют больше ввода, чем сна (5000)?
Чтобы добавить другое средство достижения 5-секундного события, можно использовать мультимедийный таймер, который похож на TTimer, но не зависит от вашего приложения. После его настройки (вы можете настроить однократный или повторяющийся) он перезвонит вам в другой поток. По своей природе это очень точно (с точностью до 1 мс). Посмотрите пример кода Delphi здесь.
Код для вызова таймера прост и поддерживается на всех платформах Windows.