EventWaitHandle-WaitAny()和WaitOne()之间的差异

本文关键字:WaitOne EventWaitHandle-WaitAny 之间 | 更新日期: 2023-09-27 17:58:13

我有3个线程,两个"worker"和一个"manager"。"Workers"线程在EventWaitHandle上等待"manager"线程将向EventWaitHandle发出信号,然后增加计数器。这些"工作线程"之间的唯一区别是一个使用EventWaitHandle.WaitAny(),另一个使用EventWaitHandle.WaitOne()

这是代码:

class Program
{
    static void Main(string[] args)
    {
        MultiThreadedJobs multyThreadedJobs = new MultiThreadedJobs();
        multyThreadedJobs.Start();
        Console.ReadLine();
        multyThreadedJobs.Stop();
    }
}
class MultiThreadedJobs : IDisposable
{
    private EventWaitHandle syncEvent;
    private EventWaitHandle[] syncEventsArray;
    private Thread managerThread;
    private Thread firstWorkerThread;
    private Thread secondWorkerThread;
    private volatile bool running = false;

    public MultiThreadedJobs() // Ctor
    {
        syncEvent = new EventWaitHandle(false, EventResetMode.AutoReset, "JobsSyncEvent");
        syncEventsArray = new EventWaitHandle[1];
        syncEventsArray[0] = syncEvent;
        managerThread = new Thread(ManagerThreadMethod);
        firstWorkerThread = new Thread(FirstWorkerThreadMethod);
        secondWorkerThread = new Thread(SecondWorkerThreadMethod);
    }
    public void Start()
    {
        running = true;
        managerThread.Start();
        firstWorkerThread.Start();
        secondWorkerThread.Start();
    }
    public void Stop()
    {
        running = false;
    }
    private void ManagerThreadMethod() // Manager Thread
    {
        while (running)
        {
            Thread.Sleep(1000);
            syncEvent.Set();
        }
    }
    private void FirstWorkerThreadMethod() // Worker Thread
    {
        int counter = 0;
        while (running)
        {
            syncEvent.WaitOne();
            counter++;
        }
    }
    private void SecondWorkerThreadMethod() // Worker Thread
    {
        int counter = 0;
        while (running)
        {
            EventWaitHandle.WaitAny(syncEventsArray);
            counter++;
        }
    }
    public void Dispose()
    {
        syncEvent.Close();
    }
}

问题是,只有第二个具有EventWaitHandle.WaitAny()的工作线程总是捕获事件,并使第一个工作线程挨饿。而不是它们中每一个的大约50/50百分比。

EventWaitHandle-WaitAny()和WaitOne()之间的差异

您正在寻找软件工程中一个非常常见的问题的解决方案,即生产者-消费者问题。维基百科的链接文章有不错的背景信息,特别是展示了如何用错误的方式来做。

你肯定在寻求一个错误的解决方案。AutoResetEvent过于简单化。您已经发现了一个问题,它不能提供公平性。它还存在许多其他问题,尤其是当生产者线程比消费者线程更快地生成作业时,它会遭遇严重的线程竞争。

示例代码过于人为,无法提供一个好的替代方案。低级锁定可以通过ReaderWriterLock/Slim类来实现。一个特别适合解决生产者/消费者问题的类是。NET 4 BlockingCollection类。支持任意数量的生产者和消费者线程,并提供节流功能,以确保当消费者无法跟上生产者的步伐时,程序不会崩溃。您可以通过使用从生产者传递给消费者线程的伪"令牌"来重写您的示例。BlockingColletion<bool>可以完成任务。

WaitHandle类使客户端可以进行异步调用并等待:单个XML Web服务(WaitHandle.WetOne),许多XML Web服务中的第一个(WaitHandle.WetAny),或所有的XML Web服务(WaitHandle.WaitAll)返回结果。如果您想在结果到达时对其进行处理,可以使用WaitHandle。WaitAny方法。此方法将指示其中一个操作已完成,并将标识已完成的操作。

这两种方法都太过时了。根据传递的参数,实现方式会有所不同。例如,WaitHandle。WaitAny方法(WaitHandle[],Int32,Boolean)等待指定数组中的任何元素接收信号,使用32位带符号整数来测量时间间隔,并指定是否在等待之前退出同步域。

等待句柄。WaitOne方法(Int32,布尔)在派生类中重写时,会阻塞当前线程直到当前WaitHandle接收到信号,使用32位带符号整数来测量时间间隔并指定是否在等待之前退出同步域。