14

我有 3 个线程,两个“工人”和一个“经理”。“工人”线程等待EventWaitHandle“经理”线程将发出信号,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%。

4

2 回答 2

13

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

您肯定在寻求一种错误的解决方案。AutoResetEvent 太简单了。你已经发现了一个问题,它不提供公平性。它还有许多其他问题,特别是当生产者线程比消费者线程更快地产生作业时,它会遭受令人讨厌的线程竞争。

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

于 2013-02-10T13:55:32.497 回答
6

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

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

WaitHandle.WaitOne Method (Int32, Boolean) 在派生类中重写时,阻塞当前线程,直到当前WaitHandle收到信号,使用32位有符号整数测量时间间隔并指定等待前是否退出同步域.

于 2013-02-13T07:14:47.097 回答