EventWaitHandle - WaitAny()和WaitOne()之间的区别

Jac*_*cob 14 .net c# multithreading

我有3个线程,两个"工人"和一个"经理"."Workers"线程等待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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Han*_*ant 13

您正在寻找解决软件工程中常见问题的解决方案,即生产者 - 消费者问题.链接的维基百科文章有相关的背景信息,特别是如何以错误的方式做到这一点.

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

示例代码过于人为,无法提供良好的替代方案.ReaderWriterLock/Slim类可以实现低级锁定.一个特别适合解决生产者/消费者问题的类是.NET 4 BlockingCollection类.支持任意数量的生产者和消费者线程并提供限制,以确保当消费者无法跟上生产者时,程序不会爆炸.您可以使用从生产者传递到消费者线程的伪"令牌"来重写样本.A BlockingColletion<bool>完成工作.


cod*_*der 6

WaitHandle的类能够为客户做异步调用和等待:一个XML Web服务(WaitHandle.WaitOne),第一次的许多XML Web服务(WaitHandle.WaitAny),或全部的许多XML Web服务(WaitHandle的. WaitAll)返回结果.如果要在结果到达时处理结果,可以使用WaitHandle.WaitAny方法.此方法将指示其中一个操作已完成,并将识别已完成的操作.

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

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