背景:
我正在开发一个已经设计了线程系统的应用程序。它远非最佳,但此时我无法重做。它不使用.net中任何较新的线程构造,只使用基本的Thread
对象,以及包装线程处理逻辑的对象。
它的一般设置是:(现在有两组或一类线程)
产生工作线程的主应用程序线程(statthread main)。
工作线程。每个对象都有一个Thread
对象,以及一个工作对象,它执行所有处理/处理线程之间的边界等。每个线程都运行作业,每个作业都有一个JobTypeID
。
我需要引入第三种类型的线程,一种用于控制工作者。这些控制消息将来自wcf Web服务(因此隐式处理此线程)。
控制消息为:{Pause / Resume,List-of-IDs}
我的目标:
我正在试图找出同步这些线程的最佳方法,这样如果一个线程正在处理一个作业,并且有一条消息说要暂停这个JobTypeID
的所有作业,它应该阻塞直到发送简历(用于该ID)。这里的问题是,在发送消息时,没有相关的工作可能正在处理,因此不需要立即执行操作,而且我也没有工作对象列表,所以我不能简单迭代每个worker并执行if-matches-then-pause。
实际问题(一般化) 你们建议我做什么来同步一组工作线程,一个产生者/经理线程和一组控制线程?
我尝试过的事情
一种方法是存储ManualResetEvent
个对象的集合,每个JobTypeID
一个,并根据传入的消息发信号并等待它们。您如何看待这种方法?我找不到有关在一个过程中拥有100多个等待句柄的最佳实践或内存/处理成本的任何信息。
另一种方法是让所有线程都等待的单个对象,以及应等待的同步集合JobTypeIDs
。我对这种方法有一些问题。使用ManualResetEvent
意味着如果我恢复一个作业ID,但其他人正在等待,我必须执行set(); reset();,这会导致一些竞争条件(即使我尝试做WaitHandle.SignalAndWait (x,x))最后,我想出了一个使用Monitor.PulseAll()的解决方案。
我还可以使用带有大量锁定对象的监视器 - 这似乎比许多等待处理器更轻量级。
另外,对于长期的问题感谢,感谢阅读!
答案 0 :(得分:2)
创建ConcurrentDictionary<JobTypeId, ManualResetEvent>
。通常,字典中没有JobTypeId
的条目。这样的条目存在的唯一时间是该作业类型应该被阻止。
当该作业类型应该被阻止时,创建一个无信号的ManualResetEvent
,并将其添加到字典中,密钥为JobTypeId
将被阻止。
然后,工作线程有一个如下所示的循环:
while (still_have_work_to_do)
{
ManualResetEvent mevent;
if (PauseDictionary.TryGetValue(myJobTypeId, out mevent))
{
// wait until the event is signaled.
mevent.WaitOne();
}
// Do more processing.
}
生成器线程还可以查询字典以查看它是否可以生成特定类型的worker。如果它无法创建工作程序,则它将丢弃该作业或将其重新排队以便稍后进行检查。你的投票频率取决于你。
在一个进程中拥有数百个WaitHandle
个对象没有特别的问题。一堆Monitor
个对象可能会占用较少的系统资源,但请记住,Monitor
(或lock
)实际上是一个互斥设备。你可以做些愚蠢的事情,使它在某些方面表现得像WaitHandle
,但这些技术并不明显,这将导致难以理解和脆弱的代码。