Ошибки с датой в циклах ожидания: как избежать бесконечных циклов в Delphi
Разработчики, работающие с языками программирования, такими как Object Pascal, используемые в среде Delphi, иногда сталкиваются с проблемами, связанными с обработкой времени. Одной из таких проблем является неправильное понимание того, как функции Time и Now возвращают дату и время. В статье мы рассмотрим, почему может возникнуть бесконечный цикл в ожидающих циклах и как его избежать.
Проблема с функцией Time
Функция Time, используемая в Delphi, возвращает время в виде плавающей точки, где целочисленная часть представляет количество дней, прошедших с 30 декабря 1899 года, а дробная часть представляет время дня с начала суток. Это может привести к тому, что в цикле ожидания, основанном на сравнении времени, цикл не завершится, так как время, возвращаемое функцией Time, всегда будет меньше сохраненного времени, которое перешло на следующий день.
Пример кода
delayTime := System.DateUtils.IncSecond(System.SysUtils.Now, PingDelay);
while (System.SysUtils.Now < delayTime) do begin
Sleep(100);
if (Terminated) then Break;
end;
В этом примере, если delayTime будет увеличен так, что перейдет на следующий день, цикл ожидания может застрять, так как функция Time всегда возвращает время, относящееся к 30 декабря 1899 года.
Подтвержденный ответ
Чтобы избежать бесконечных циклов, необходимо использовать функцию SysUtils.Now, которая возвращает текущее время и дату. Это позволяет избежать проблемы, связанной с переходом на следующий день, так как Now учитывает и дату, и время.
delayTime := System.DateUtils.IncSecond(System.SysUtils.Now, PingDelay);
while (System.SysUtils.Now < delayTime) do begin
Sleep(100);
if (Terminated) then Break;
end;
Альтернативный ответ
Для более надежной и независимой от системного времени механизмы ожидания можно использовать механизмы ожидания объектов, такие как Waitable Timer и Event Object. Это позволяет избежать зависимости от системного времени и предотвратить бесконечные циклы, даже при смене часового пояса или других изменениях в системных настройках времени.
type
TPingThread = class(TThread)
private
termEvent: TEvent;
hDelayTimer: THandle;
function Delay(Seconds: Integer): Boolean;
...
protected
procedure TerminatedSet; override;
...
end;
...
function TPingThread.Delay(Seconds: Integer): Boolean;
var
dueTime: LARGE_INTEGER;
arr: array[0..1] of THandle;
which: DWORD;
begin
// Установка таймера
// ...
// Ожидание сигнала от таймера или события завершения
which := WaitForMultipleObjects(2, arr, FALSE, INFINITE);
// ...
end;
...
procedure TPingThread.Execute;
begin
// Цикл выполнения потока
// ...
while not Terminated do
begin
// ...
if not Delay(PingDelay) then
Break;
// ...
end;
// ...
end;
Такой подход позволяет потоку действительно "спать" до истечения времени ожидания, не тратя при этом циклы процессора.
Заключение
Использование функции SysUtils.Now и механизмов ожидания объектов позволяет избежать бесконечных циклов в ожидающих циклах и повышает надежность программы. Разработчикам следует быть внимательными при работе с функциями, возвращающими время, и использовать альтернативные методы ожидания при необходимости.
Советы по предотвращению бесконечных циклов в ожидающих циклах в Delphi, связанных с обработкой даты и времени.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.