我有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();
}
}
问题是,只有EventWaitHandle.WaitAny()
的第二个工作线程总是捕获事件,并使第一个工作线程饿死。而不是大约50/50的百分比。
答案 0 :(得分:13)
您正在寻找解决软件工程中常见问题的解决方案Producer-consumer problem。链接的维基百科文章有相关的背景信息,特别是如何以错误的方式做到这一点。
你当然正在寻求一种错误的解决方案。 AutoResetEvent太简单了。您已经发现了一个问题,它没有提供公平性。它的许多其他问题,特别是当生产者线程比消费者线程更快地生成作业时,它会遇到令人讨厌的线程竞争。
示例代码过于人为,无法提供良好的替代方案。 ReaderWriterLock / Slim类可以实现低级锁定。一个特别适合解决生产者/消费者问题的类是.NET 4 BlockingCollection类。支持任意数量的生产者和消费者线程并提供限制,以确保当消费者无法跟上生产者时,程序不会爆炸。您可以使用从生产者传递到消费者线程的伪“令牌”来重写样本。 BlockingColletion<bool>
完成工作。
答案 1 :(得分: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位有符号整数来测量时间间隔并指定 是否在等待之前退出同步域。