首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Delegate.BeginInvoke 2.0中BeginRead的实现中,.NET是如何向等待处理发出信号的?

在Delegate.BeginInvoke 2.0中BeginRead的实现中,.NET是如何向等待处理发出信号的?
EN

Stack Overflow用户
提问于 2016-06-02 14:47:49
回答 2查看 212关注 0票数 1

下面是System.IO.FileStream.BeginRead方法的实现,就像在.NET 2.0中一样。

如您所见,实现将操作传递给ReadDelegateBeginInvoke方法。

但是,在这样做之前,它会初始化一个AutoResetEvent,然后在它上调用WaitOne

但是,我不知道ReadDelegate如何向AutoResetEvent发送信号,因为它不会有任何引用。

你能解释一下这是怎么回事吗?

代码语言:javascript
运行
复制
[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);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-02 16:12:51

反编译程序无法帮助您检索原始源代码中的注释。它可以从.NET发行版获得SSCLI20 2.0。它是这样写的:

代码语言:javascript
运行
复制
       // 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是从它的正常用法向后使用。只有在什么都没有发生的时候,它才被设定。

票数 1
EN

Stack Overflow用户

发布于 2016-06-02 14:58:43

我在问题中提到的AutoResetEvent似乎不是用来指示ReadDelegate的完成,因为它已经通过回调被委托给委托上的BeginInvoke方法,而是确保调用了EndRead,从而保持了整个BeginXXXEndXXX操作作为一个单一单元的原子性。

这可以从同一类的EndRead方法的代码中推断出来。

代码语言:javascript
运行
复制
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表示,这是一个类级实例变量。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37595163

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档