2009-08-11 8 views
2

のは、私のような公開されたインターフェースを持っているとしましょう:C#糸通し機構

interface IMyService 
{ 
    MyResult MyOperation(); 
} 

この操作は同期であり、値を返します。

私の実装インタフェースは、次の操作を行うことがあります。

  • はこれがためですイベント#のイベント#用
  • 待ち1
  • 待ち2

を非同期メソッドを呼び出します私が協力しているサードパーティのCOMオブジェクト。

このコードでは、それは非常にランダムである、順序のいずれかで発生する可能性があり、次の

public MyResult MyOperation() 
{ 
    _myCOMObject.AsyncOperation(); 

    //Here I need to wait for both events to fire before returning 
} 

private void MyEvent1() 
{ 
    //My Event 1 is fired in this handler 
} 

private void MyEvent2() 
{ 
    //My Event 2 is fired in this handler 
} 

私の二つの事象に似ています。

私はこれを同期するために使用できる適切なスレッド機構は何ですか? 2番目のイベントの待機を開始する前にManualResetEventを使用していましたが、両方のイベントで簡単に使用する方法は見当たりませんでした。これらの2つのイベントはMyOperation()の戻り値を作成できる変数を設定します。

いい実装のアイデアですか?私は第三者オブジェクトが実装される方法を制御できません。

答えて

4

2つのManualResetEventはあなたのためのトリックを行う必要があります。 _myCOMObject.AsyncOperation()に電話する前に、それらをfalseに初期化してください。このように:コメントの

private ManualResetEvent event1; 
private ManualResetEvent event2; 

public MyResult MyOperation() 
{ 
    event1 = new ManualResetEvent(false); 
    event2 = new ManualResetEvent(false); 

    _myCOMObject.AsyncOperation(); 

    WaitHandle.WaitAll(new WaitHandle[] { event1, event2 }); 
} 

private void MyEvent1() 
{ 
    event1.Set(); 
} 

private void MyEvent2() 
{ 
    event2.Set(); 
} 

編集

感謝。私は使用する待機呼び出しを変更しましたWaitAll

+0

これは意味があります。私の混乱は、複数のManualResetEventsでReset()を呼び出す場所に嘘をつきました。また、2つのスレッドが同時に関数を呼び出せないようにMyOperation()に呼び出し全体をロックする必要があります。 – jonathanpeppers

+2

これは完璧な解決策ですが、2つのWaitOneブロッキングコールの代わりにWaitAll(下図参照)を使用します.WaitAllはブロッキングについての詳細なコンテキストを提供し、潜在的にはより良いスケジュールを立てる可能性があります。 – meandmycode

+0

フィードバックいただきありがとうございます。私は私の答えを更新しました。 –

0

私はあなたの質問を理解しているか分からないが、私はそれを得た場合、AutoResetEvent.WaitAllあなたの問題を解決するようです。複数のハンドラを設定することができ、すべてのハンドラが設定されている場合にのみ解放されます。次のように

http://msdn.microsoft.com/en-us/library/z6w25xa6.aspx

2

私の実装例は次のとおりです。

namespace ConsoleApplication1 
{ 

    class Program 
    { 
     private static WaitHandle[] waitHandles; 
     private static event EventHandler Evt1; 
     private static event EventHandler Evt2; 

     static void Main(string[] args) 
     { 
      waitHandles = new WaitHandle[]{ 
       new ManualResetEvent(false), 
       new ManualResetEvent(false) 
      }; 

      Evt1 += new EventHandler(Program_Evt1); 
      Evt2 += new EventHandler(Program_Evt2); 

      OnEvt1(); 
      OnEvt2(); 

      WaitHandle.WaitAll(waitHandles); 

      Console.WriteLine("Finished"); 
      Console.ReadLine(); 
     } 

     static void Program_Evt2(object sender, EventArgs e) 
     { 
      Thread.Sleep(2000); 
      ((ManualResetEvent)waitHandles[0]).Set(); 
     } 

     static void Program_Evt1(object sender, EventArgs e) 
     { 
      ((ManualResetEvent)waitHandles[1]).Set(); 
     } 

     static void OnEvt1() 
     { 
      if (Evt1 != null) 
       Evt1(null, EventArgs.Empty); 
     } 

     static void OnEvt2() 
     { 
      if (Evt2 != null) 
       Evt2(null, EventArgs.Empty); 
     } 


    } 
} 

、私はそれがこの例とWaitAll機能

乾杯の目的のために眠る作る

アンドリュー

PS別の例では、AsyncCallbackを使用することになります。本当にすばやく汚れた例ですが、ドアを開くためにもっと多くのキーを提供します:-)。お役に立てれば!!

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     private static WaitHandle[] waitHandles; 
     private static event EventHandler Evt1; 
     private static event EventHandler Evt2; 

     static void Main(string[] args) 
     { 
      waitHandles = new WaitHandle[]{ 
       new ManualResetEvent(false), 
       new ManualResetEvent(false) 
      }; 

      var callabck1 = new AsyncCallback(OnEvt1); 
      var callabck2 = new AsyncCallback(OnEvt2); 

      callabck1.Invoke(new ManualResetResult(null, (ManualResetEvent)waitHandles[0])); 
      callabck2.Invoke(new ManualResetResult(null, (ManualResetEvent)waitHandles[1])); 

      WaitHandle.WaitAll(waitHandles); 

      Console.WriteLine("Finished"); 
      Console.ReadLine(); 

     } 

     static void OnEvt1(IAsyncResult result) 
     { 
      Console.WriteLine("Setting1"); 
      var handle = result.AsyncWaitHandle; 
      ((ManualResetEvent)handle).Set(); 
     } 

     static void OnEvt2(IAsyncResult result) 
     { 
      Thread.Sleep(2000); 
      Console.WriteLine("Setting2"); 
      var handle = result.AsyncWaitHandle; 
      ((ManualResetEvent)handle).Set(); 
     } 

    } 

    public class ManualResetResult : IAsyncResult 
    { 
     private object _state; 
     private ManualResetEvent _handle; 

     public ManualResetResult(object state, ManualResetEvent handle) 
     { 
      _state = state; 
      _handle = handle; 
     } 

     #region IAsyncResult Members 

     public object AsyncState 
     { 
      get { return _state; } 
     } 

     public WaitHandle AsyncWaitHandle 
     { 
      get { return _handle; } 
     } 

     public bool CompletedSynchronously 
     { 
      get { throw new NotImplementedException(); } 
     } 

     public bool IsCompleted 
     { 
      get { throw new NotImplementedException(); } 
     } 

     #endregion 
    } 
} 
関連する問題