简体   繁体   中英

Releasing many threads from one event signal

I have a application where multiple threads have to wait on an event to indicate that new data is available in a list. My expectation was that I could use an AutoResetEvent, WaitOne on it in each thread, and then when the data is available Set the event.

However, because it is auto reset the first thread clears the event and doesn't release the other threads. Now I could presumably make it a manual reset and implement a counter, but my feeling is that this is a common problem and so there must be a standard way to do it, but searching the docs I couldn't find one.

Any help? Here is some sample code that doesn't release all the threads:

    static AutoResetEvent eve = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        var threads = new List<Thread>();
        for (int i = 0; i < 10; ++i)
        {
            int iCopy = i;
            var t = new Thread(() => thread(iCopy));
            threads.Add(t);
            t.Start();
        }
        Console.WriteLine("Pausing");
        Thread.Sleep(5000);
        eve.Set();
        foreach (var t in threads) t.Join();
        Console.WriteLine("All done");
        Console.ReadKey();
    }

    static void thread(int n)
    {
        eve.WaitOne();
        Console.WriteLine("Thread {0}", n);
    }

Just use the ManualResetEvent in the place of AutoRestEvent. There is not need for counter. I tried , it worked below is the code.

    static ManualResetEvent eve = new ManualResetEvent(false);

    static void Main(string[] args)
    {
        var threads = new List<Thread>();
        for (int i = 0; i < 10; ++i)
        {
            int iCopy = i;
            var t = new Thread(() => thread(iCopy));
            threads.Add(t);
            t.Start();
        }
        Console.WriteLine("Pausing");
        Thread.Sleep(5000);
        eve.Set();
        foreach (var t in threads) t.Join();
        Console.WriteLine("All done");
        Console.ReadKey();
    }

    static void thread(int n)
    {
        eve.WaitOne();
        Console.WriteLine("Thread {0}", n);
    }

I have a application where multiple threads have to wait on an event to indicate that new data is available in a list. My expectation was that I could use an AutoResetEvent, WaitOne on it in each thread, and then when the data is available Set the event.

You have a bit of a XY Problem , however thankfully you included what your "X" was (Make the threads get new data from a list once it is available).

Based off of your description I think you would be better off using a BlockingCollection , you can spin up as many threads as you want and they will all block till new data is available, as soon as data is available they unblock and take data till there is none left then re-block.

using System;
using System.Collections.Concurrent;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static BlockingCollection<int> _items = new BlockingCollection<int>(); 
        static void Main(string[] args)
        {
            //Start up 4 threads
            var threads = new Thread[4];
            for (int i = 0; i < threads.Length; i++)
            {
                var iCopy = i;
                threads[i] = new Thread(() => ProcessItems(iCopy));
                threads[i].IsBackground = true;
                threads[i].Start();
            }

            //Give the threads 5 items to process.
            for (int i = 0; i < 5; i++)
            {
                _items.Add(i);
            }

            Console.WriteLine("All items queued, sleeping 2 seconds");
            Thread.Sleep(2000);

            //Give the threads 10 more items to process.
            for (int i = 0; i < 10; i++)
            {
                _items.Add(i);
            }
            _items.CompleteAdding();
            Console.WriteLine("Marked adding complete");

            foreach (var t in threads) t.Join();

            Console.WriteLine("All threads complete");
            Console.ReadLine();
        }

        static void ProcessItems(int i)
        {
            var rnd = new Random(i);
            foreach (var item in _items.GetConsumingEnumerable())
            {
                Console.WriteLine("Thread {0} Processing item {1}", i, item);

                //Simulate a random amount work
                Thread.Sleep(rnd.Next(100, 500));
            }
        }
    }
}

If you really want to release all the waiting threads just once, use an array of semaphores, one for each thread. When you want them all to go, send one unit to each semaphore in a loop.

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