在C#中同步共享资源的集合

时间:2013-10-07 11:52:02

标签: c# multithreading

我在C#应用程序中有一个静态的共享资源集合(文本处理器类),它可以响应关键字。每个处理器都是有状态的,因此在多线程上下文中不起作用。我正在寻找一种组织这些的好方法,以便我可以对它们进行线程安全访问。

例如,我可以在每个处理器中嵌入一个同步对象

public abstract class TextProcessor
{
    protected internal readonly object sync = new object();

    public abstract void Run( string text );
}

public class DocumentProcessor
{
    private static Dictionary<string,TextProcessor> s_procMap = ...;

    public void Run( string [] words1, string[] words2 )
    {
        ThreadPool.QueueUserWorkItem( Process, words1 );
        ThreadPool.QueueUserWorkItem( Process, words2 );
    }

    private void Process( object arg )
    {
        foreach( var word in words )
        {
            var proc = s_processor[word];
            lock( proc.sync )
            {
                proc.Run( word );
            }
        }
    }

假设我无法将我的处理器重写为无状态(这是一种选择,但由于重构量而成为最后的选择),有没有更好的方法来表达它?

2 个答案:

答案 0 :(得分:2)

当前方法的问题是单个忙TextProcessor可以停止处理剩余的单词。如果您改为给每个TextProcessor一个(线程安全的)单词队列,那么您可以在不阻塞的情况下将工作排队并让TextProcessor出列并按顺序处理这些单词。

查看TPL Dataflow libraryActionBlock。它处理排队,处理Task的开始以及最终关闭Task,以防再也没有工作。

请注意,当没有工作排队时,不会阻止任何线程。这是一个重要的可伸缩性属性。

答案 1 :(得分:1)

如果你真的不想改变处理器...那么我会做一个包装器。

public class ProcWrapper
{
  private TextProcessor _proc;
  private ActionBlock<string> _actBlock;

  public ProcWrapper(TextProcessor proc)
  {
    _proc = proc;

    _actBlock = new ActionBlock<string[]>(word=>
    {
      _proc.Run(word);
    });
  }

  public void AddWord(string words)
  {
    _actBlock.Post(word);
  }

  public void WaitForCompletion()
  {
    _actBlock.Completion.Wait();
  }
}

使用它与以前的方式类似:

Dictionary<string,ProcWrapper> s_procMap = ...;

void Run( string [] words )
{
  // NOTE: This assumes the same thread will access s_procMap.
  foreach(var word in words)
    s_procMap[word].AddWord(word);
}

我认为这与你正在寻找的很接近。

请点击http://msdn.microsoft.com/en-us/library/hh228603.aspx了解DataFlow TPLhttp://msdn.microsoft.com/en-us/library/hh194684.aspx的详细信息,了解ActionBlock<T>的具体信息。