我想要达到的目标与标题相同。在我的问题中,我的主线程中有一个数据列表,我希望主线程触发一个事件,子线程可以处理该事件以使用数据列表。无论如何在C#中做到这一点?
首先想到的方法是让子线程不断检查数据列表。但我想通过让主线程通知子线程,我可以节省让子线程在后台不断运行的开销。
答案 0 :(得分: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();
}
如果要添加正常终止,您可以使用task cancellation mechanisms来弹出GetConsumingEnumerable
枚举器。我没有说明这可以在这里,但它并不是非常困难,并且已经有很多例子。
答案 1 :(得分:2)
我会考虑使用TPL DataFlow中的ActionBlock
- 特别是如果没有要求按顺序处理消息的话。作为奖励,无需在代码中管理消费者线程。
以下是一个例子:
// 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();
答案 2 :(得分:1)
ObservableCollection模板类可能是您问题的解决方案:
http://msdn.microsoft.com/en-us/library/ms668604.aspx
表示在何时提供通知的动态数据集合 项目被添加,删除或刷新整个列表。
答案 3 :(得分:0)
一个非常简单的方法是,当主线程准备好使用数据时,主线程只需生成带有数据副本的线程池线程。无需发出信号;无需运行后台线程。