下面是System.IO.FileStream.BeginRead
方法的实现,就像在.NET 2.0中一样。
如您所见,实现将操作传递给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);
}
发布于 2016-06-02 16:12:51
反编译程序无法帮助您检索原始源代码中的注释。它可以从.NET发行版获得SSCLI20 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操作,因此阻塞操作没有任何意义。因此,初始化将要设置的对象是有意的。WaitOne()调用再次重置它,因此在上一次调用完成之前第二次调用BeginRead()将阻塞并避免竞争条件。EndRead()通过再次设置它来解除阻塞。
可能的精神上的颠簸是,ARE是从它的正常用法向后使用。只有在什么都没有发生的时候,它才被设定。
发布于 2016-06-02 14:58:43
我在问题中提到的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
表示,这是一个类级实例变量。
https://stackoverflow.com/questions/37595163
复制相似问题