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

2023-09-04 07:50:03 作者:现实在疼也别忘记微笑。

是多线程调用下面的模式可以接受的一个.net的的FileStream ?

Is the following pattern of multi-threaded calls acceptable to a .Net FileStream?

若干线程调用这样的方法:

Several threads calling a method like this:

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类说道:

I'm confused because the documentation seems unclear to me. For example, the FileStream class says:

这类型的任何公共静态成员是线程安全的。所有实例成员不能保证是线程安全的。

Any public static members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

但BeginRead的文档似乎考虑其在飞行中多次读请求:

But the documentation for BeginRead seems to contemplate having multiple read requests in flight:

同时进行多个异步请求呈现请求完成顺序不确定的。

Multiple simultaneous asynchronous requests render the request completion order uncertain.

多个读取允许在飞行与否?写?这是为了确保位置通话之间的数据流的位置,以寻找和调用的BeginRead ?还是那把锁需要被一路持有到 EndRead ,所以只有一个读或一次写在飞行?

Are multiple reads permitted to be in flight or not? Writes? Is this the appropriate way to secure the location of the Position of the stream between the call to Seek and the call to BeginRead? Or does that lock need to be held all the way to EndRead, hence only one read or write in flight at a time?

据我所知,回调将发生在不同的线程,和我的处理状态缓存搞定的方式,将允许多个飞行中读取

I understand that the callback will occur on a different thread, and my handling of state, buffer handle that in a way that would permit multiple in flight reads.

此外,没有人知道在哪里的文档中找到这些问题的答案?或一篇文章写的那些知道的人?我一直在寻找,并不能找到任何东西。

Further, does anyone know where in the documentation to find the answers to these questions? Or an article written by someone in the know? I've been searching and can't find anything.

相关文章:

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

FileStream class Seek method BeginRead method EndRead IAsyncResult interface

修改了一些新的信息

一个快速检查与反射器显示的BeginRead确实捕捉到流位置为每次通话状态(NativeOverlapped结构的某些字段)。看来,EndRead不征询流的位置,至少不会以任何明显的方式。这不是结论性的,很明显,因为它可能是在一个非显而易见的方式,或者它可以是不支持的由底层机API

A quick check with Reflector shows that BeginRead does capture the stream position into per-call state (some fields of the NativeOverlapped structure). It appears that EndRead doesn't consult the stream position, at least not in any obvious way. This is not conclusive, obviously, because it could be in a non-obvious way or it could be unsupported by the underlying native API.

推荐答案

是的,文档比较粗略。不知道更好的文档,很遗憾。

Yes, the documentation is sketchy. No clue for better docs, unfortunately.

编辑:其实在Windows乔·达菲的书并发编程有第8章APM这也解释了异步API,IAsyncResult的等(本好书,作者)。不过这里的根本问题是,MSDN说,实例变量不是线程安全的,因此需要适当的同步。

Actually Joe Duffy's book Concurrent Programming on Windows has Chapter 8 APM which explains the async API, IAsyncResult and such (good book and author). Still the fundamental issue here is that MSDN says that instance variables are not thread safe, hence the need for appropriate synchronization.

所以,你有多个线程蹬掉的BeginRead上theFile的同一个实例?该BeginRead的页面做不过提到这一点:EndRead必须调用一次每次调用BeginRead的失败来结束读取过程开始另外的读取会导致意外的行为,例如僵局。你也呼吁寻求在theFile对象,而其他线程可能在执行他们的BeginRead回调的中间。没有安全可言。

So you have multiple threads kicking off BeginRead on the same instance of theFile? The BeginRead page does mention this however: "EndRead must be called exactly once for every call to BeginRead. Failing to end a read process before beginning another read can cause undesirable behavior such as deadlock." Also you are calling Seek on theFile object while other threads might be in the middle of executing their BeginRead callbacks. Not safe at all.

 
精彩推荐
图片推荐