2009-08-11 90 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 
} 

我的兩個事件可以順序發生,這是很隨機的。

我可以使用什麼正確的線程機制來同步它?在我必須開始等待第二個事件之前,我使用了ManualResetEvent,並且沒有看到用於這兩個事件的簡單方法。這兩個事件設置了變量,使我可以爲MyOperation()創建返回值。

關於良好實施的任何想法?我無法控制第三方對象的實現方式。

回答

4

兩個ManualResetEvent s應該爲你做的伎倆。在致電_myCOMObject.AsyncOperation()之前,只需將它們初始化爲假。就像這樣:

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()上調用哪一個,並且我還必須將整個調用鎖定到MyOperation(),以便兩個線程不能同時調用該函數。 – jonathanpeppers 2009-08-11 16:29:25

+2

儘管這是一個非常好的解決方案,但我會使用WaitAll(如下所示)而不是兩個WaitOne阻塞調用,WaitAll爲系統提供了有關阻塞的更多上下文,並有可能爲更好的調度提供機會。 – meandmycode 2009-08-11 16:31:32

+0

感謝您的反饋。我已經更新了我的答案。 – 2009-08-11 17:56:20

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