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

时间:2010-04-02 01:39:47

标签: c# .net multithreading file-io 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?
}

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调用和Position调用之间保护流的BeginRead位置的适当方法吗?或者锁定是否需要一直保持到EndRead,因此一次只能在飞行中读取或写入一次?

我知道回调将发生在另一个线程上,我对statebuffer的处理方式可以允许多次飞行中的读取。

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

相关文档:

FileStream class
Seek method
BeginRead method
EndRead
IAsyncResult interface

使用一些新信息进行修改

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

1 个答案:

答案 0 :(得分:1)

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

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

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