【问题标题】:Releasing many threads from one event signal从一个事件信号中释放多个线程
【发布时间】:2015-07-26 18:54:55
【问题描述】:

我有一个应用程序,其中多个线程必须等待一个事件以指示列表中有新数据可用。我的期望是我可以在每个线程中使用 AutoResetEvent、WaitOne,然后在数据可用时设置事件。

但是,因为它是自动重置的,所以第一个线程会清除事件并且不会释放其他线程。现在我大概可以让它手动重置并实现一个计数器,但我的感觉是这是一个常见的问题,所以必须有一个标准的方法来做到这一点,但是搜索我找不到的文档。

有什么帮助吗?下面是一些不释放所有线程的示例代码:

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

【问题讨论】:

  • 您似乎在寻找 CountdownEventSemaphore
  • ManualResetEvent

标签: c# multithreading


【解决方案1】:

只需使用 ManualResetEvent 代替 AutoRestEvent。不需要柜台。我试过了,下面是代码。

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

【讨论】:

  • 对不起,这不起作用,因为没有人清除事件,所以一旦线程被清除访问权限,它们就不会再次被锁定。
  • 您能详细说明您的要求吗?如果你想再次阻塞线程,你可以再次调用Reset。
【解决方案2】:

我有一个应用程序,其中多个线程必须等待一个事件以指示列表中有新数据可用。我的期望是我可以在每个线程中使用 AutoResetEvent、WaitOne,然后在数据可用时设置事件。

你有一点XY Problem,但幸运的是你包含了你的“X”是什么(一旦它可用,就让线程从列表中获取新数据)。

根据您的描述,我认为您最好使用BlockingCollection,您可以根据需要启动任意数量的线程,它们都会阻塞,直到有新数据可用,一旦数据可用,它们就会解除阻塞并取数据,直到没有数据,然后重新阻塞。

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

【讨论】:

    【解决方案3】:

    如果您真的只想释放所有等待的线程一次,请使用一组信号量,每个线程一个。当您希望它们全部消失时,循环发送一个单元到每个信号量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 2018-10-28
      • 2016-03-23
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      • 2016-01-23
      相关资源
      最近更新 更多