locked
Waiting for multiple events RRS feed

  • Question

  • Hi!

    Is it possible to wait for multiple ManualResetEvents in .NET cf? If not, is it possible to interrupt a thread that is blocking on an event?

    Thanks in advance,
    Nille
    Monday, August 8, 2005 9:45 AM

Answers

  • yep it is possible to do it, use the static class WaitHandle you call the WaitAll method wich takes as parameters an array of ManualResetEvents, here is the example from the whidbey documentation,



    using System;
    using System.IO;
    using System.Security.Permissions;
    using System.Threading;

    // Request permission to create and write files to C:\TestTest.
    [assembly: FileIOPermissionAttribute(SecurityAction.RequestMinimum,
         All = @"C:\TestTest")]

    class Test
    {
        static void Main()
        {
            const int numberOfFiles = 5;
            string dirName = @"C:\TestTest";
            string fileName;

            byte[] byteArray;
            Random randomGenerator = new Random();

            ManualResetEvent[] manualEvents =
                new ManualResetEvent[numberOfFiles];
            State stateInfo;

            if(!Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }

            // Queue the work items that create and write to the files.
            for(int i = 0; i < numberOfFiles; i++)
            {
                fileName = string.Concat(
                    dirName, @"\Test", i.ToString(), ".dat");

                // Create random data to write to the file.
                byteArray = new byte[1000000];
                randomGenerator.NextBytes(byteArray);

                manualEventsIdea = new ManualResetEvent(false);

                stateInfo =
                    new State(fileName, byteArray, manualEventsIdea);

                ThreadPool.QueueUserWorkItem(new WaitCallback(
                    Writer.WriteToFile), stateInfo);
            }
       
            // Since ThreadPool threads are background threads,
            // wait for the work items to signal before exiting.
            WaitHandle.WaitAll(manualEvents);
            Console.WriteLine("Files written - main exiting.");
        }
    }

    // Maintain state to pass to WriteToFile.
    class State
    {
        public string fileName;
        public byte[] byteArray;
        public ManualResetEvent manualEvent;

        public State(string fileName, byte[] byteArray,
            ManualResetEvent manualEvent)
        {
            this.fileName = fileName;
            this.byteArray = byteArray;
            this.manualEvent = manualEvent;
        }
    }

    class Writer
    {
        static int workItemCount = 0;
        Writer() {}

        public static void WriteToFile(object state)
        {
            int workItemNumber = workItemCount;
            Interlocked.Increment(ref workItemCount);
            Console.WriteLine("Starting work item {0}.",
                workItemNumber.ToString());
            State stateInfo = (State)state;
            FileStream fileWriter = null;

            // Create and write to the file.
            try
            {
                fileWriter = new FileStream(
                    stateInfo.fileName, FileMode.Create);
                fileWriter.Write(stateInfo.byteArray,
                    0, stateInfo.byteArray.Length);
            }
            finally
            {
                if(fileWriter != null)
                {
                    fileWriter.Close();
                }

                // Signal Main that the work item has finished.
                Console.WriteLine("Ending work item {0}.",
                    workItemNumber.ToString());
                stateInfo.manualEvent.Set();
            }
        }
    }

     


    Tuesday, August 9, 2005 9:14 AM

All replies

  • yep it is possible to do it, use the static class WaitHandle you call the WaitAll method wich takes as parameters an array of ManualResetEvents, here is the example from the whidbey documentation,



    using System;
    using System.IO;
    using System.Security.Permissions;
    using System.Threading;

    // Request permission to create and write files to C:\TestTest.
    [assembly: FileIOPermissionAttribute(SecurityAction.RequestMinimum,
         All = @"C:\TestTest")]

    class Test
    {
        static void Main()
        {
            const int numberOfFiles = 5;
            string dirName = @"C:\TestTest";
            string fileName;

            byte[] byteArray;
            Random randomGenerator = new Random();

            ManualResetEvent[] manualEvents =
                new ManualResetEvent[numberOfFiles];
            State stateInfo;

            if(!Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }

            // Queue the work items that create and write to the files.
            for(int i = 0; i < numberOfFiles; i++)
            {
                fileName = string.Concat(
                    dirName, @"\Test", i.ToString(), ".dat");

                // Create random data to write to the file.
                byteArray = new byte[1000000];
                randomGenerator.NextBytes(byteArray);

                manualEventsIdea = new ManualResetEvent(false);

                stateInfo =
                    new State(fileName, byteArray, manualEventsIdea);

                ThreadPool.QueueUserWorkItem(new WaitCallback(
                    Writer.WriteToFile), stateInfo);
            }
       
            // Since ThreadPool threads are background threads,
            // wait for the work items to signal before exiting.
            WaitHandle.WaitAll(manualEvents);
            Console.WriteLine("Files written - main exiting.");
        }
    }

    // Maintain state to pass to WriteToFile.
    class State
    {
        public string fileName;
        public byte[] byteArray;
        public ManualResetEvent manualEvent;

        public State(string fileName, byte[] byteArray,
            ManualResetEvent manualEvent)
        {
            this.fileName = fileName;
            this.byteArray = byteArray;
            this.manualEvent = manualEvent;
        }
    }

    class Writer
    {
        static int workItemCount = 0;
        Writer() {}

        public static void WriteToFile(object state)
        {
            int workItemNumber = workItemCount;
            Interlocked.Increment(ref workItemCount);
            Console.WriteLine("Starting work item {0}.",
                workItemNumber.ToString());
            State stateInfo = (State)state;
            FileStream fileWriter = null;

            // Create and write to the file.
            try
            {
                fileWriter = new FileStream(
                    stateInfo.fileName, FileMode.Create);
                fileWriter.Write(stateInfo.byteArray,
                    0, stateInfo.byteArray.Length);
            }
            finally
            {
                if(fileWriter != null)
                {
                    fileWriter.Close();
                }

                // Signal Main that the work item has finished.
                Console.WriteLine("Ending work item {0}.",
                    workItemNumber.ToString());
                stateInfo.manualEvent.Set();
            }
        }
    }

     


    Tuesday, August 9, 2005 9:14 AM
  • Hi! Thanks for responding, and thanks for the example!

    However, I'm using .NET Compact Framework and WaitHandle.WaitAny isn't available in cf, as it seems (am I right about this...?). Any other way of doing it?

    I'm using the events to synchronize with a DLL containing native C++, and I want to be able to interrupt the synchronization e.g. upon application exit. I have just noticed that it doesn't work very well to pass event handles between the .NET CF application and the DLL, for some reason. Anyone experienced any problems with this? Any event handle I receive from the DLL or pass to the DLL will be invalid, which means that the wait methods will return immediatelly. One might think that this application would block forever:



    public class MyBlockingClass
    {
       public static void Main(String[] args)
       {
          ManualResetEvent evt = new ManualResetEvent(false);
          evt.Handle = CreateNativeEvent();
          evt.WaitOne(); // This should block forever, but it doesn't...
       }
    }

    [DllImport("myDll.dll", EntryPoint="CreateNativeEvent")]
    private static extern IntPtr CreateNativeEvent();

     


    // And the dll:

    extern "C" __declspec(dllexport) HANDLE CreateNativeEvent()
    {
       // ManualReset + No initial owner
       return ::CreateEvent(NULL, true, false, NULL);
    }

    Any ideas about this?

    Thanks in advance,
    Nille
    Tuesday, August 9, 2005 9:28 AM
  • nope man, i can see there is no waitall method on waithandle on the cf, sorry i can't help you further, try posting the question on the Smart Devices---> .NET Compact Framework Forum, i'm sure you'll have better luck in thereBig Smile
    Tuesday, August 9, 2005 4:46 PM
  • Thanks,
    Tuesday, August 9, 2005 7:53 PM
  • Thanks Nille
    Wednesday, August 10, 2005 5:34 PM