明确地实现IAsyncResult

时间:2009-01-01 23:04:52

标签: c# concurrency asynchronous iasyncresult

我一般都对部分实现接口持谨慎态度。但是,IAsyncResult有点特殊情况,因为它支持几种截然不同的使用模式。您使用/查看的频率使用AsyncState / AsyncCallback模式,而不是仅使用EndInvoke调用AsyncWaitHandle,或使用IsCompleted轮询(yuck) ?

相关问题:Detecting that a ThreadPool WorkItem has completed/waiting for completion

考虑这个类(非常近似,需要锁定):

public class Concurrent<T> {
    private ManualResetEvent _resetEvent;
    private T _result;

    public Concurrent(Func<T> f) {
        ThreadPool.QueueUserWorkItem(_ => {
                                         _result = f();
                                         IsCompleted = true;
                                         if (_resetEvent != null)
                                             _resetEvent.Set();
                                     });
    }

    public WaitHandle WaitHandle {
        get {
            if (_resetEvent == null)
                _resetEvent = new ManualResetEvent(IsCompleted);
            return _resetEvent;
        }

    public bool IsCompleted {get; private set;}
    ...

它有WaitHandle(懒惰创建,正如IAsyncResult文档中所述)和IsCompleted,但我没有看到AsyncState的合理实现({{ 1}}?)。那么实施{return null;}是否有意义?请注意,并行扩展库中的IAsyncResult确实实现了Task,但只隐式实现了IAsyncResult

2 个答案:

答案 0 :(得分:3)

好像你有几个问题。让我们单独处理它们

懒洋洋地创建WaitHandle

是的,这是最正确的方法。你应该以线程安全的方式做到这一点,但懒惰就是这样。

但诀窍是处理WaitHandle。 WaitHandle是IDisposable的基础,必须及时处理。 IAsycResult的文档不包括这种情况。最好的方法是在EndInvoke中。 BeginInvoke的文档明确指出,对于每个BeginInvoke,必须有相应的EndInvoke(或BeginRead / EndRead)。这是处理WaitHandle的最佳位置。

如何实施AsyncState?

如果你看一下返回IAsyncResult的标准BCL API,它们中的大多数都采用状态参数。这通常是从AsyncState返回的值(有关示例,请参阅Socket API)。对于任何返回IAsyncResult的API BeginInvoke样式API,包含一个类型为对象的状态变量是一个好习惯。没有必要,但良好的做法。

在状态变量的abscence中,返回null是可以接受的。

IsCompleted API

这将高度依赖于创建IAsyncResult的实现。但是,是的,你应该实现它。

答案 1 :(得分:2)

  • 根据我的经验,只是在没有等待或首先被回叫的情况下调用EndInvoke很少有用
  • 提供回调有时是不够的,因为您的客户可能希望一次等待多个操作(WaitAny,WaitAll)
  • 我从未对IsCompleted进行过调查,确实如此!因此,您可以保存IsCompleted的实现,但它非常简单,似乎不值得让您的客户感到惊讶。

因此,异步可调用方法的合理实现应该真正提供完全实现的IAsyncResult。

顺便说一句,您通常不需要自己实现IAsyncResult,只需返回Delegate.BeginInvoke返回的内容即可。有关示例,请参阅System.IO.Stream.BeginRead的实现。