FileStream的同步要求.(开始/结束)(读/写)

Dou*_*ean 9 .net c# file-io multithreading filestream

.Net 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?
}
Run Code Online (Sandbox Code Playgroud)

在哪里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
    }
}
Run Code Online (Sandbox Code Playgroud)

我很困惑因为文档似乎对我不清楚.例如,FileStream类说:

此类型的任何公共静态成员都是线程安全的.任何实例成员都不保证是线程安全的.

但是BeginRead的文档似乎考虑在飞行中有多个读取请求:

多个同时发生的异步请求使请求完成顺序不确定.

允许多次读取是否在飞行中?写?这是在PositionSeek调用和调用之间保护流的位置的适当方法BeginRead吗?或者是否需要一直保持锁定EndRead,因此一次只能进行一次读写操作?

据我所知,回调将发生在不同的线程,和我的处理state,buffer处理在的方式,将允许多个飞行中读取.

此外,是否有人知道文档中的哪个位置可以找到这些问题的答案?或者有人知道的文章?我一直在寻找,找不到任何东西.

相关文件:

FileStream类
Seek方法
BeginRead方法
EndRead
IAsyncResult接口

使用一些新信息进行编辑

使用Reflector快速检查显示BeginRead确实将流位置捕获到每个调用状态(NativeOverlapped结构的某些字段).似乎EndRead不会查询流的位置,至少不是以任何明显的方式.显然,这不是决定性的,因为它可能是一种非显而易见的方式,或者它可能不受底层本机API的支持.

Chr*_*s O 1

是的,文档很粗略。不幸的是,没有更好的文档的线索。

编辑:实际上 Joe Duffy 的书《Windows 上的并发编程》有第 8 章 APM,其中解释了异步 API、IAsyncResult 等(好书和作者)。这里的基本问题仍然是 MSDN 说实例变量不是线程安全的,因此需要适当的同步。

那么您有多个线程在 theFile 的同一个实例上启动 BeginRead 吗?不过,BeginRead 页面确实提到了这一点:“每次调用 BeginRead 时,必须调用一次 EndRead。如果在开始另一次读取之前未能结束读取过程,可能会导致死锁等不良行为。” 此外,您正在对 File 对象调用 Seek,而其他线程可能正在执行其 BeginRead 回调。一点也不安全。

  • 解释 MSDN 让恶魔从我的鼻子里飞出来;-) 该特定页面肯定是自相矛盾的(MSDN 文档错误并不罕见),尽管我认为死锁语句是正确的,并且多个同时异步请求是错误的,但这只是一个假设。 (2认同)