2010-04-02 42 views
9

.Net FileStream可以接受以下多線程調用模式嗎?FileStream的同步要求(開始/結束)(讀/寫)

的多個線程調用這樣的方法:

ulong offset = whatever; // different for each thread 
byte[] buffer = new byte[8192]; 
object state = someState; // unique for each call, hence also for each thread 

lock(theFile) 
{ 
    theFile.Seek(whatever, SeekOrigin.Begin); 
    IAsyncResult result = theFile.BeginRead(buffer, 0, 8192, AcceptResults, state); 
} 

if(result.CompletedSynchronously) 
{ 
    // is it required for us to call AcceptResults ourselves in this case? 
    // or did BeginRead already call it for us, on this thread or another? 
} 

其中AcceptResults是:

void AcceptResults(IAsyncResult result) 
{ 
    lock(theFile) 
    { 
     int bytesRead = theFile.EndRead(result); 

     // if we guarantee that the offset of the original call was at least 8192 bytes from 
     // the end of the file, and thus all 8192 bytes exist, can the FileStream read still 
     // actually read fewer bytes than that? 

     // either: 
     if(bytesRead != 8192) 
     { 
      Panic("Page read borked"); 
     } 

     // or: 
     // issue a new call to begin read, moving the offsets into the FileStream and 
     // the buffer, and decreasing the requested size of the read to whatever remains of the buffer 
    } 
} 

我很困惑,因爲文件似乎我不清楚。例如,FileStream類說:

此類型的任何公共靜態成員都是線程安全的。任何實例成員不保證是線程安全的。

但的BeginRead的文件似乎考慮在飛行中有多個讀取請求:

同時進行多個異步請求呈現請求完成順序不確定。

允許多個讀取在飛行中嗎?寫?這是確保呼叫Seek和呼叫BeginRead之間的流的Position位置的適當方式嗎?或者該鎖需要一直保持到EndRead,因此一次只能在一次讀取或寫入數據?

據我所知,回調將發生在另一個線程上,我的處理statebuffer處理,允許在飛行中讀取多個。

此外,有沒有人知道在文檔的哪裏找到這些問題的答案?或者知道某人寫的文章?我一直在尋找,找不到任何東西。

相關文章:

FileStream class
Seek method
BeginRead method
EndRead
IAsyncResult interface

編輯了一些新的信息

使用Reflector快速檢查顯示BeginRead確實將流位置捕獲到每個調用狀態(NativeOverlapped結構的某些字段)。看起來,EndRead並未諮詢流的位置,至少沒有以任何明顯的方式。這顯然不是確定的,因爲它可能不是明顯的方式,或者它可能不被底層的本地API支持。

+0

+1寫得很好的問題。 – SLaks 2010-04-02 01:43:18

回答

1

是的,文件是粗略的。不幸的是,沒有關於更好的文檔的線索。

編輯:實際上Joe Duffy的書Concurrent Programming on Windows has Chapter 8 APM which explain async API,IAsyncResult and such as(good book and author)。這裏的基本問題仍然是MSDN說實例變量不是線程安全的,因此需要適當的同步。

因此,您有多個線程在File的相同實例上啓動BeginRead?然而,BeginRead頁面提到了這一點:「每次調用BeginRead時都必須調用EndRead一次,在開始另一次讀取之前未能結束讀取過程可能導致不良行爲,如死鎖。」此外,您正在調用SeeF onFile對象,而其他線程可能正在執行其BeginRead回調。不安全。

+1

如果一個線程正在尋找而另一個線程正在執行其回調,爲什麼要重要?大概回調意味着所請求的閱讀已完成,對嗎?我更關心的是在BeginRead和匹配回調之間的時間內調用Seek。除非我錯過了某些東西,否則上面的代碼每次調用BeginRead時都會調用EndRead一次,因此當它返回的IAsyncResult爲CompletedSynchronously時,BeginRead是否調用它的回調會導致一些不確定性。 – 2010-04-03 02:56:47

+0

是的,它的每個BeginRead都有一個EndRead。但是,不能保證EndRead會在另一個線程啓動它的BeginRead之前被調用,該鎖無法保護該場景。 – 2010-04-03 03:03:09

+0

呵呵,在這裏你可能沒問題,BeginRead頁面會說:「在Windows上,小於64 KB的所有I/O操作將會同步完成,以獲得更好的性能,異步I/O可能會影響小於64 KB的緩衝區的性能。所以你*保證所有的讀取事實上都是由你的鎖序列化的。 但是,如果所有線程都通過鎖和同步讀取進行序列化,爲什麼還要使用異步API呢? – 2010-04-03 03:17:27