2009-04-18 21 views
2

私のマルチスレッドの知識はまだまだ基本的なものであり、ここではいくつかの参考になるでしょう。私は次のメソッドを持つインタフェース、(WCF)からIOperationInvoker持っている:このインタフェースの具体的な実装を考えると非同期操作内の非同期操作

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

を、私は別々のスレッドで基礎となる実装を呼び出しながら、同じインターフェイスを実装する必要があります。 (理由を疑問に思っている場合は、具体的な実装は別のアパートメント状態にある必要があるレガシーCOMオブジェクトを呼び出します)。私は私自身で返さAsyncResultをラップする必要があると思っていたので、私は戻って私たちがきたスレッドに取得することができます

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); 
    } 
} 

:現時点では

、私はこのような何かをやっていますスプールアップされました...しかし、正直言って私は少し深みがあります。すべてのポインタ?

多くのおかげで、

ジェームズ

答えて

1

は非同期、同期メソッドを実装する最も簡単な方法は、デリゲートに入れ、そして得られたデリゲートにBeginInvokeEndInvokeメソッドを使用することです。これにより、スレッドプールスレッドで同期メソッドが実行され、BeginInvokeIAsyncResultの実装を返しますので、実装する必要はありません。しかし、IAsyncResultに少し余分なデータを密輸してIOperationInvoker.InvokeEndを返す必要があります。 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(); 
    } 
} 

それは、そうでない場合は、彼らが不適切SignalExceptionのようなメソッドにアクセスしたり、途中でResultを読んで、クライアントコードがIAsyncResult実装を見ることができない正当性が重要です。このクラスは、必要でなければWaitHandleの実装(例ではManualResetEvent)を構築しない方が効率的になりますが、これは100%正しくなるようにするのは難しいです。またThreadManualResetEventは、を実装するすべてのオブジェクトで実行する必要があるので、Endの実装で処分することができます。そして明らかに、Endは、適切なクラスの実装がキャスト例外よりも優れた例外を取得していることを確認する必要があります。私は、非同期実装の本質的な仕組みをあいまいにするので、これらのやその他の詳細を残しました。

+0

非常にありがとうございます。バリー - 私はそれを行こうと思います! –

関連する問題