2009-04-18 160 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