2009-04-18 163 views
2

我的多线程知识仍然非常简陋,所以在这里真的很欣赏一些指针。我有它具有以下方法的接口,IOperationInvoker(从WCF):异步操作中的异步操作

IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 

给出一个具体实现这个接口的,我要实现相同的接口,同时呼吁在一个单独的线程的底层实现。 (如果你想知道为什么,具体的暗示调用一个传统的COM对象,它需要处于不同的公寓状态)。

目前,我在做这样的事情:

public StaOperationSyncInvoker : IOperationInvoker { 
    IOperationInvoker _innerInvoker; 
    public StaOperationSyncInvoker(IOperationInvoker invoker) { 
     this._innerInvoker = invoker; 
    } 


    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
    { 
     Thread t = new Thread(BeginInvokeDelegate); 
     InvokeDelegateArgs ida = new InvokeDelegateArgs(_innerInvoker, instance, inputs, callback, state); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(ida); 
     // would do t.Join() if doing syncronously 
     // how to wait to get IAsyncResult? 
     return ida.AsyncResult; 
    } 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
    { 
     // how to call invoke end on the 
     // thread? could we have wrapped IAsyncResult 
     // to get a reference here? 
     return null; 
    } 

    private class InvokeDelegateArgs { 
     public InvokeDelegateArgs(IOperationInvoker invoker, object instance, object[] inputs, AsyncCallback callback, object state) 
     { 
      this.Invoker = invoker; 
      this.Instance = instance; 
      this.Inputs = inputs; 
      this.Callback = callback; 
      this.State = state; 
     } 

     public IOperationInvoker Invoker { get; private set; } 
     public object Instance { get; private set; } 
     public AsyncCallback Callback { get; private set; } 
     public IAsyncResult AsyncResult { get; set; } 
     public Object[] Inputs { get; private set; } 
     public Object State { get; private set; } 
    } 
    private static void BeginInvokeDelegate(object data) 
    { 
     InvokeDelegateArgs ida = (InvokeDelegateArgs)data; 
     ida.AsyncResult = ida.Invoker.InvokeBegin(ida.Instance, ida.Inputs, ida.Callback, ida.State); 
    } 
} 

我想我需要的收官返回AsyncResult用我自己的,这样我就可以回到我们已经线程被卷了起来...但老实说,我有点出于我的深度。任何指针?

非常感谢,

詹姆斯

回答

1

最简单的方法来实现同步异步方法是把它变成一个委托,并使用上产生的委托BeginInvokeEndInvoke方法。这将在线程池线程上运行同步方法,并且BeginInvoke将返回IAsyncResult实现,因此您不必实现它的胆量。但是,您确实需要将一点额外数据走私到由IOperationInvoker.InvokeEnd返回的IAsyncResult。您可以通过创建IAsyncResult的实现来轻松地完成此操作,该实现将所有内容委托给内部IAsyncResult,但具有用于包含代理的额外字段,以便当IAsyncResult实例传递给InvokeEnd时,您可以访问代理以在其上调用EndInvoke

然而,你的问题的细读之后,我看到你需要使用一个明确的线程与COM设置等

你需要做的是正确地实现IAsyncResult什么。由于IAsyncResult将包含同步所需的所有位,因此几乎所有内容都来自此。

这是一个非常简单但不是非常有效的IAsyncResult的实现。它封装了所有基本特性:传递参数,同步事件,回调实现,从异步任务传播异常并返回结果。

using System; 
using System.Threading; 

class MyAsyncResult : IAsyncResult 
{ 
    object _state; 
    object _lock = new object(); 
    ManualResetEvent _doneEvent = new ManualResetEvent(false); 
    AsyncCallback _callback; 
    Exception _ex; 
    bool _done; 
    int _result; 
    int _x; 

    public MyAsyncResult(int x, AsyncCallback callback, object state) 
    { 
     _callback = callback; 
     _state = state; 
     _x = x; // arbitrary argument(s) 
    } 

    public int X { get { return _x; } } 

    public void SignalDone(int result) 
    { 
     lock (_lock) 
     { 
      _result = result; 
      _done = true; 
      _doneEvent.Set(); 
     } 
     // never invoke any delegate while holding a lock 
     if (_callback != null) 
      _callback(this); 
    } 

    public void SignalException(Exception ex) 
    { 
     lock (_lock) 
     { 
      _ex = ex; 
      _done = true; 
      _doneEvent.Set(); 
     } 
     if (_callback != null) 
      _callback(this); 
    } 

    public object AsyncState 
    { 
     get { return _state; } 
    } 

    public WaitHandle AsyncWaitHandle 
    { 
     get { return _doneEvent; } 
    } 

    public bool CompletedSynchronously 
    { 
     get { return false; } 
    } 

    public int Result 
    { 
     // lock (or volatile, complex to explain) needed 
     // for memory model problems. 
     get 
     { 
      lock (_lock) 
      { 
       if (_ex != null) 
        throw _ex; 
       return _result; 
      } 
     } 
    } 

    public bool IsCompleted 
    { 
     get { lock (_lock) return _done; } 
    } 
} 

class Program 
{ 
    static void MyTask(object param) 
    { 
     MyAsyncResult ar = (MyAsyncResult) param; 
     try 
     { 
      int x = ar.X; 
      Thread.Sleep(1000); // simulate lengthy work 
      ar.SignalDone(x * 2); // demo work = double X 
     } 
     catch (Exception ex) 
     { 
      ar.SignalException(ex); 
     } 
    } 

    static IAsyncResult Begin(int x, AsyncCallback callback, object state) 
    { 
     Thread th = new Thread(MyTask); 
     MyAsyncResult ar = new MyAsyncResult(x, callback, state); 
     th.Start(ar); 
     return ar; 
    } 

    static int End(IAsyncResult ar) 
    { 
     MyAsyncResult mar = (MyAsyncResult) ar; 
     mar.AsyncWaitHandle.WaitOne(); 
     return mar.Result; // will throw exception if one 
          // occurred in background task 
    } 

    static void Main(string[] args) 
    { 
     // demo calling code 
     // we don't need state or callback for demo 
     IAsyncResult ar = Begin(42, null, null); 
     int result = End(ar); 
     Console.WriteLine(result); 
     Console.ReadLine(); 
    } 
} 

它的正确性客户端代码无法看到IAsyncResult执行很重要,否则他们可能不适当访问诸如SignalException方法或阅读Result过早。如果没有必要构建WaitHandle实现(示例中为ManualResetEvent),则该类可以变得更高效,但如果没有必要,该类很难100%正确。此外,ThreadManualResetEvent可以并应该在End实施中处理,应该使用实现IDisposable的所有对象完成。很明显,End应该检查以确保它已经获得了正确的类的实现以获得比抛出的异常更好的异常。我已经将这些和其他细节留给了他们,因为它们掩盖了异步实现的基本机制。

+0

非常感谢Barry--我会放弃这一切! – 2009-04-20 14:32:23