2

我想要达到的目标与标题相同。在我的问题中,我的主线程中有一个数据列表,我想让主线程触发一个可由子线程处理的事件以使用数据列表。反正有在 C# 中做吗?

我首先想到的方法是让子线程不断检查数据列表。但我认为通过让主线程通知子线程,我可以节省让子线程在后台不断运行的开销。

4

4 回答 4

5

您可能应该在这里使用生产者-消费者模式。父线程将充当生产者,子线程将充当消费者。父级将生成数据并以通知子级(无需轮询)的方式发布数据,以便它可以使用它。幸运的是,.NET 使这个BlockingCollection类变得简单。这是您的代码可能的样子。

class Producer
{
  private BlockingCollection<YourData> queue;

  public Producer(BlockingCollection<YourData> q)
  {
    queue = q;
  }

  public void GenerateItems()
  {
    while (...)
    {
      YourData item = GenerateItem();
      queue.Add(item);
    }
  }
}

class Consumer
{
  public Consumer(BlockingCollection<YourData> queue)
  {
    Task.Factory.StartNew(
      () =>
      {
        foreach (YourData item in queue.GetConsumingEnumerable())
        {
          ProcessItem(item);
        }
      ), TaskCreationOptions.LongRunning);
  }

  private void ProcessItem(YourData item)
  {
    // Add logic to process each data item here.
  }

}

因此,我们有一个Producer生成数据项并将它们添加到的类,BlockingCollection以及一个Consumer在这些数据项可用时删除它们的类。GetConsumingEnumerable行为就像Take如果队列中没有任何内容,它将调用者置于空闲状态。所以基本上调用线程没有做任何类型的繁忙轮询(至少不是在微不足道的意义上),所以它是资源友好的。

这是一个如何将所有内容粘合在一起的示例。

public static void Main()
{
  var queue = new BlockingCollection<YourData>();
  var producer = new Producer(queue);
  var consumer = new Consumer(queue);
  producer.GenerateItems();
}

如果要添加优雅终止,您可以使用任务取消机制让枚举器弹出。GetConsumingEnumerable我还没有展示这怎么可能在这里,但这并不是非常困难,而且已经有很多例子了。

于 2013-09-11T14:38:09.850 回答
2

我会考虑使用ActionBlockTPL DataFlow - 特别是如果不需要按顺序处理消息。作为奖励,无需在代码中管理消费者线程。

这是一个例子:

 // Create an ActionBlock that performs some work. 
 var workerBlock = new ActionBlock<MessageData>(

  data=>
     {
         DoWork(data); // method consuming data
     },

  // Specify a maximum degree of parallelism. 
  new ExecutionDataflowBlockOptions
  {
     MaxDegreeOfParallelism = maxDegreeOfParallelism
  });

// Post messageCount messages to the queue
for (int i = 0; i < messageCount; i++)
 {
   var messageData = new MessageData();
   workerBlock.Post(messageData);
 }

 // Signal that Producer has no more data to send
 workerBlock.Complete();

 // Wait for all messages to propagate through the network.
 workerBlock.Completion.Wait();
于 2013-09-11T17:01:31.730 回答
1

ObservableCollection 模板类可能是您问题的解决方案:

http://msdn.microsoft.com/en-us/library/ms668604.aspx

表示一个动态数据集合,它在添加、删除项目或刷新整个列表时提供通知。

于 2013-09-11T09:46:35.927 回答
0

当主线程准备好使用数据时,一个非常简单的方法是让您的主线程简单地生成一个带有数据副本的线程池线程。无需发信号;不需要已经运行后台线程。

于 2013-09-11T18:45:05.397 回答