Frage

Ich habe eine app in Delphi 2006 geschrieben, die regelmäßig von einer Plattendatei an anderer Stelle in einem Netzwerk liest (100Mb Ethernet). Gelegentlich wird die Lese über das Netzwerk eine sehr lange Zeit in Anspruch nimmt (wie 20 Sekunden) und die App gefriert, als das Lesen aus einem Ruhe-Handler in dem Haupt-Thread ausgeführt wird.

OK, ich könnte die Lese Betrieb genommen in einen eigenen Thread ist, aber was ich möchte wissen, ob es möglich ist, ein Timeout für eine Dateioperation angeben, dass so können Sie aufgeben und gehen und etwas anderes tun, oder die Tatsache, berichtet, dass die Lese etwas früher als 20 Sekunden später verhakt hat.

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

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

Lösung

Öffnen Sie die Datei für asynchrone Zugriff durch die File_Flag_Overlapped Flagge einschließlich des CreateFile nennen. Der Pass in einer TOverlapped Aufzeichnung, wenn Sie ReadFile rufen, und wenn die Lese nicht sofort abgeschlossen ist, wird die Funktion zurückgeben früh. Sie können steuern, wie lange Sie für das Lesen, um eine vollständige warten von WaitForSingleObject auf den Fall ruft Sie in der TOverlapped Struktur speichern. Sie können sogar MsgWaitForMultipleObjects zu warten, verwenden; dann können Sie, sobald die Lese abgeschlossen ist oder eine Nachricht eintrifft, benachrichtigt je nachdem was zuerst kommt, so dass Ihr Programm überhaupt nicht hängen muss. Nachdem Sie Nachrichten beenden Verarbeitung, können Sie noch einmal überprüfen, ob die E / A mit GetOverlappedResult, Lebenslauf Warte abgeschlossen ist, oder telefonisch unter CancelIo auf dem I / O aufgeben. Stellen Sie sicher, dass Sie die Dokumentation für alle diese Funktionen sorgfältig lesen; asynchrones I / O ist nicht trivial.

Andere Tipps

Nachdem Sie den Lesevorgang zu einem Thread verschoben haben, können Sie den Wert von timeGetTime zurück speichern, bevor das Lesen:

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

und die Prüfung im Ruhe Handler, wenn es zu lange gedauert hat.

Beispiel:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top