同步.net 4中的多个线程

时间:2011-12-29 17:15:51

标签: .net multithreading synchronization worker

背景: 我正在开发一个已经设计了线程系统的应用程序。它远非最佳,但此时我无法重做。它不使用.net中任何较新的线程构造,只使用基本的Thread对象,以及包装线程处理逻辑的对象。

它的一般设置是:(现在有两组或一类线程)

  • 产生工作线程的主应用程序线程(statthread main)。

  • 工作线程。每个对象都有一个Thread对象,以及一个工作对象,它执行所有处理/处理线程之间的边界等。每个线程都运行作业,每个作业都有一个JobTypeID

    < / LI>

我需要引入第三种类型的线程,一种用于控制工作者。这些控制消息将来自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()的解决方案。

我还可以使用带有大量锁定对象的监视器 - 这似乎比许多等待处理器更轻量级。

另外,对于长期的问题感谢,感谢阅读!

1 个答案:

答案 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,但这些技术并不明显,这将导致难以理解和脆弱的代码。