以下是 .NET 2.0 中 System.IO.FileStream.BeginRead
方法的实现。
如您所见,该实现将操作传递给ReadDelegate
的BeginInvoke
方法。
但是,在执行此操作之前,它会初始化一个AutoResetEvent
,然后对其调用WaitOne
。
但是,我不明白ReadDelegate
如何向AutoResetEvent
发出信号,因为它不会提及它。
你能解释一下这是如何工作的吗?
[HostProtection(SecurityAction.LinkDemand, ExternalThreading=true)]
public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
if (!this.CanRead)
{
__Error.ReadNotSupported();
}
Interlocked.Increment(ref this._asyncActiveCount);
ReadDelegate delegate2 = new ReadDelegate(this.Read);
if (this._asyncActiveEvent == null)
{
lock (this)
{
if (this._asyncActiveEvent == null)
{
this._asyncActiveEvent = new AutoResetEvent(true);
}
}
}
this._asyncActiveEvent.WaitOne();
this._readDelegate = delegate2;
return delegate2.BeginInvoke(buffer, offset, count, callback, state);
}
反编译器无法帮助您检索原始源代码中的注释。 可从SSCLI20发行版中获得 .NET 2.0。 它读起来是这样的:
// To avoid a race with a stream's position pointer & generating race
// conditions with internal buffer indexes in our own streams that
// don't natively support async IO operations when there are multiple
// async requests outstanding, we will block the application's main
// thread if it does a second IO request until the first one completes.
if (_asyncActiveEvent == null) {
lock(this) {
if (_asyncActiveEvent == null)
_asyncActiveEvent = new AutoResetEvent(true);
}
}
bool r = _asyncActiveEvent.WaitOne();
BCLDebug.Assert(r, "AutoResetEvent didn't get a signal when we called WaitOne!");
BCLDebug.Assert(_readDelegate == null && _writeDelegate == null,
"Expected no other readers or writers!");
因此,如果_asyncActiveEvent
为 null,则不会有任何其他异步 I/O 操作正在运行,因此阻止该操作没有任何意义。 因此,初始化要设置的 ARE 是非常有意的。 WaitOne() 调用会再次重置它,因此在前一个调用完成之前再次调用 BeginRead() 将阻止并避免竞争条件。 EndRead() 通过再次设置来解锁它。
可能的心理减速带是 ARE 的使用与其正常使用相反。 它仅在什么都没有发生时设置。
似乎我在问题中提到的AutoResetEvent
不是用来表示ReadDelegate
完成的,因为它已经通过回调委托给委托上的 BeginInvoke
方法,而是为了确保调用EndRead
,从而保持完整BeginXXX
的原子性,并将EndXXX
操作作为一个单元。
这可以从同一类的EndRead
方法的代码中推断出来。
public virtual int EndRead(IAsyncResult asyncResult)
{
if (asyncResult == null)
{
throw new ArgumentNullException("asyncResult");
}
if (this._readDelegate == null)
{
throw new ArgumentException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple"));
}
int num = -1;
try
{
num = this._readDelegate.EndInvoke(asyncResult);
}
finally
{
this._readDelegate = null;
this._asyncActiveEvent.Set();
this._CloseAsyncActiveEvent(Interlocked.Decrement(ref this._asyncActiveCount));
}
return num;
}
AutoResetEvent
由标识_asyncActiveEvent
表示,这是一个类级实例变量。