简体   繁体   中英

C# Threading Mechanism

Let's say I have an exposed interface as such:

interface IMyService 
{
    MyResult MyOperation();
}

This operation is synchronous and returns a value.

My implemented interface has to do the following:

  • Call an asynchronous method
  • Wait for event #1
  • Wait for event #2

This is due to a 3rd party COM object I am working with.

This code looks similar to the following

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
}

My two events can happen in either order, it is quite random.

What is the proper threading mechanism I can use to synchronize this? I was using ManualResetEvent before I had to start waiting for the second event, and have not seen an easy way to use it for both events. These 2 events set variables that allow me to create the return value for MyOperation().

Any ideas on a good implementation for this? I have no control over the way the 3rd party object is implemented.

Two ManualResetEvent s should do the trick for you. Just initialize them to false before you call the _myCOMObject.AsyncOperation() . Like this:

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

Edit

Thanks for the comments. I've changed the wait call to use WaitAll

My implementation example is as follows:

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


    }
}

I make it sleep for the purposes of this example and the WaitAll functionality

Cheers,

Andrew

PS another example would be using AsyncCallback, really quick and dirty example, but gives you more keys to open the door with :-) . Hope this helps!!

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

I am not sure I understood your question, but AutoResetEvent.WaitAll seems to solve your problem, if I got it right. It allows you to set more than one handler and it will only be released when all are set.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM