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百分比。
您正在寻找软件工程中一个非常常见的问题的解决方案,即生产者-消费者问题。维基百科的链接文章有不错的背景信息,特别是展示了如何用错误的方式来做。
你肯定在寻求一个错误的解决方案。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位带符号整数来测量时间间隔并指定是否在等待之前退出同步域。