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

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

最佳答案

您可能应该在此处使用生产者-消费者模式。父线程将充当生产者,子线程将充当消费者。父级将产生数据并以通知子级(无需轮询)的方式发布它,以便其可以使用它。幸运的是,.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();
}

如果要添加优美的终止,可以使用task cancellation mechanisms弹出GetConsumingEnumerable枚举器。我没有在这里展示过它如何,但是并不是很难,而且已经有很多例子了。

10-07 19:11
查看更多