C # Механизм резьбы - PullRequest
       33

C # Механизм резьбы

2 голосов
/ 11 августа 2009

Допустим, у меня есть открытый интерфейс как таковой:

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, прежде чем мне пришлось ждать второго события, и я не видел простого способа использовать его для обоих событий. Эти 2 события устанавливают переменные, которые позволяют мне создать возвращаемое значение для MyOperation ().

Есть идеи по хорошей реализации для этого? У меня нет контроля над реализацией стороннего объекта.

Ответы [ 3 ]

4 голосов
/ 11 августа 2009

Два 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

2 голосов
/ 11 августа 2009

Мой пример реализации выглядит следующим образом:

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

Приветствия

Andrew

P.S. другим примером будет использование 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
    }
}
0 голосов
/ 11 августа 2009

Я не уверен, что понял ваш вопрос, но AutoResetEvent.WaitAll, похоже, решит вашу проблему, если я правильно понял. Он позволяет вам установить более одного обработчика, и он будет освобожден, только когда все установлены.

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

...