以下多线程调用模式对于 .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和BeginRead之间保护流的Position位置的适当方式?还是需要一直保持该锁定直到EndRead,因此一次只能有一个读取或写入请求?
我理解回调将在不同的线程上发生,并且我的处理state、buffer的方式可以允许多个读取请求同时进行。
此外,有人知道在文档中哪里可以找到这些问题的答案吗?或者由内行人撰写的文章?我一直在搜索,但找不到任何信息。
相关文档:
带有一些新信息的编辑
使用Reflector进行快速检查显示,BeginRead确实将流位置捕获到每个调用状态中(NativeOverlapped结构的某些字段)。看起来EndRead没有以任何明显的方式查询流位置。这显然并不是最终结论,因为它可能以非明显的方式存在,或者在底层本地API中不受支持。