.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
,因此一次只能在飞行中读取或写入一次?
我知道回调将发生在另一个线程上,我对state
,buffer
的处理方式可以允许多次飞行中的读取。
此外,有没有人知道文档中的哪个位置可以找到这些问题的答案?或者有人知道的文章?我一直在寻找,找不到任何东西。
相关文档:
FileStream class
Seek method
BeginRead method
EndRead
IAsyncResult interface
使用一些新信息进行修改
使用Reflector快速检查显示BeginRead确实将流位置捕获到每个调用状态(NativeOverlapped结构的某些字段)。似乎EndRead不会查询流的位置,至少不是以任何明显的方式。显然,这不是决定性的,因为它可能是非显而易见的方式,或者它可能不受底层本机API的支持。
答案 0 :(得分:1)
是的,文档很粗略。不幸的是,没有更好的文档的线索。
编辑:实际上Joe Duffy的书“Windows上的并发编程”有第8章APM,它解释了异步API,IAsyncResult等(好书和作者)。这里的基本问题仍然是MSDN说实例变量不是线程安全的,因此需要适当的同步。所以你有多个线程在同一个文件实例上启动BeginRead?然而,BeginRead页面确实提到了这一点:“每次调用BeginRead时都必须调用一次EndRead。在开始另一次读取之前未能结束读取过程会导致不良行为,例如死锁。”此外,您正在调用Seek on theFile对象,而其他线程可能正在执行其BeginRead回调。根本不安全。