我要达到的目标与标题相同。在我的问题中,我的主线程中有一个数据列表,我想让主线程触发一个事件,该事件可由子线程处理以消耗数据列表。无论如何,用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
枚举器。我没有在这里展示过它如何,但是并不是很难,而且已经有很多例子了。