2010-11-17 27 views
4

我有一個用Delphi 2006編寫的應用程序,它定期從位於網絡上的其他位置(100Mb以太網)的磁盤文件讀取。偶爾,通過網絡讀取需要很長時間(如20秒)並且應用程序凍結,因爲讀取是從主線程中的空閒處理程序完成的。使用Delphi讀取文件時實現超時

好吧,我可以把讀操作放到它自己的線程中,但是我想知道的是是否可以指定文件操作的超時時間,以便您可以放棄並執行其他操作或者報告讀取已經在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 ; 

回答

9

打開通過包括File_Flag_Overlapped標誌,當你調用CreateFileasynchronous access文件。當您致電ReadFile時傳入TOverlapped記錄,並且如果讀取沒有立即完成,該功能將提前返回。您可以通過在存儲在TOverlapped結構中的事件調用WaitForSingleObject來控制等待讀取完成的時間。您甚至可以使用MsgWaitForMultipleObjects等待;那麼只要讀完一條消息到達,您會收到通知,以先到者爲準,因此您的程序根本不需要掛起。處理完消息後,可以通過調用CancelIo再次檢查I/O是否已完成,並返回GetOverlappedResult,繼續等待,或放棄I/O。確保您仔細閱讀所有這些功能的文檔;異步I/O不是微不足道的。

+0

很好的解釋!但是,德爾福的例子,將不勝感激,我認爲... – 2010-11-17 14:55:31

+0

我敢肯定,但我會留給那些更有能力(或更有動力)比我,@Workshop的人。正如我所說,這不是微不足道的,所以我不打算現場編寫一個例子。 – 2010-11-17 15:05:10

0

你移動的讀操作線程後,您可以通過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 
+0

問題是:如果在線程中讀取障礙物,它將保持打開的文件,所以即使我檢測到它花費了1秒以上的時間,我也無法重試,直到線程到達最後的條款,即直到20秒過去。 – rossmcm 2010-11-17 03:09:12

+0

那麼,根據您用來打開文件的共享模式,您應該可以打開第二個句柄,並嘗試與另一個線程並行。不過,您應該小心,像覆蓋共享數據或啓動太多線程一樣。 – TheNewbie 2010-11-17 03:39:32