2009-08-11 2 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()에 대한 반환 값을 만들 수있는 변수를 설정합니다.

좋은 구현에 대한 아이디어가 있습니까? 제 3 자 객체가 구현되는 방식을 제어하지 못합니다.

답변

4

두 개의 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()을 호출하는 곳에서 거짓말을했고, MyOperation()에 대한 전체 호출을 잠궈 두 스레드가 동시에 함수를 호출 할 수 없도록해야합니다. – jonathanpeppers

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