реализация тайм-аута при чтении файла с Delphi - PullRequest
4 голосов
/ 17 ноября 2010

У меня есть приложение, написанное на Delphi 2006, которое регулярно читает файлы на диске, расположенные в других местах сети (100 МБ Ethernet).Иногда чтение по сети занимает очень много времени (например, 20 секунд), и приложение зависает, так как чтение выполняется из обработчика простоя в главном потоке.

ОК, я мог бы поместить операцию чтения вэто собственный поток, но я хотел бы знать, можно ли указать тайм-аут для файловой операции, чтобы вы могли сдаться и пойти и сделать что-то еще, или сообщить о том, что чтение зацепилось немного раньшечем через 20 секунд.

function ReadWithTimeout (var Buffer     ;
                              N       : integer ; 
                              Timeout : integer) : boolean ;

begin
Result := false
try
    SetReadTimeout (Timeout) ;          //  <==========================???
    FileStream.Read (Buffer, N) ;
    Result := true ;
except 
    ... 
    end ;
end ;

Ответы [ 2 ]

9 голосов
/ 17 ноября 2010

Откройте файл для асинхронного доступа , включив флаг File_Flag_Overlapped при вызове CreateFile.Передайте запись TOverlapped при вызове ReadFile, и если чтение не завершится немедленно, функция вернется рано.Вы можете контролировать время ожидания завершения чтения, вызывая WaitForSingleObject для события, которое вы храните в структуре TOverlapped.Вы можете даже использовать MsgWaitForMultipleObjects для ожидания;затем вы можете получить уведомление, как только чтение завершит или , когда придет сообщение, в зависимости от того, что произойдет раньше, поэтому вашей программе вообще не нужно будет зависать.После завершения обработки сообщений вы можете еще раз проверить, завершен ли ввод-вывод с помощью GetOverlappedResult, возобновить ожидание или отказаться от ввода-вывода, вызвав CancelIo.Убедитесь, что вы внимательно прочитали документацию по всем этим функциям;асинхронный ввод / вывод не тривиален.

0 голосов
/ 17 ноября 2010

После перемещения операции чтения в поток вы можете сохранить значение, возвращаемое timeGetTime, перед чтением:

isReading := true;
try
  startedAt := timeGetTime;
  FileStream.Read (Buffer, N);
  ...
finally
  isReading := false;
end;

и проверить в обработчике простоя, если оно заняло слишком много времени.

Например:

function ticksElapsed( FromTicks, ToTicks : cardinal ) : cardinal;
begin
  if FromTicks < ToTicks
    then Result := ToTicks - FromTicks
    else Result := ( high(cardinal) - FromTicks ) + ToTicks; // There was a wraparound
end;

...

if isReading and ( ticksElapsed( startedAt, timeGetTime ) > 10 * 1000 ) // Taken too long? ~10s
then // Do something
...