在两个线程之间交替

本文关键字:线程 之间 两个 | 更新日期: 2023-09-27 18:36:04

我正在构建的应用程序从某个源读取日志并将其显示在网格上。日志的大小可以是几 MB 到几 GB。为了防止内存出现任何问题,我使用网格并一次对日志进行 500 行分页。这就是我希望做的:

我想创建一个线程,该线程将读取日志并每次将它们写入大约 500 行的文件,然后向另一个线程发出日志已写入的信号。然后,另一个线程将读取文件并在网格上显示行,并向第一个线程发出它已完成读取的信号。这种情况一直持续到没有更多日志要写入文件为止。

是否可以像这样在线程之间切换?

在两个线程之间交替

是的,当然,这是生产者-消费者模式的变体。

您可以在此处使用一些基本的构建块,例如 ThreadAutoResetEvent ."生产者"从日志中读取行并将它们发布到文件中(也许您可以使用内存缓冲区代替?),然后向另一个线程发出信号以读取它们:

AutoResetEvent consumerEvent = new AutoResetEvent(false);
AutoResetEvent producerEvent = new AutoResetEvent(false);
// producer code
while(/* lines still available */)
{
    // read 500 lines
    // write to shared file
    consumerEvent.Set(); // signal consumer thread
    producerEvent.WaitOne(); // wait to be signaled to continue
}

和消费者代码:

while(/* termination not received */)
{
    consumerEvent.WaitOne(); // wait for the producer to finish     
    // read lines from file and put them in the grid
    producerEvent.Set(); // allow producer to read more logs
}

这将允许使用者读取文件和生产者读取更多日志并准备下一批之间实现一定程度的并行性。

当生产者完成日志处理后,它可以在文件中放置一条特殊的终止消息,以指示使用者正常退出。

这是一种策略,它非常低级且容易出错。您可以完全跳过共享文件,并以 BlockingCollection 的形式使用内存缓冲区。

定义一个 ProducerTask 类来保存一些文本行:

class ProducerTask 
{
    public String[] Lines { get; set; }
}

此任务一次可容纳 500 行。

然后使用TaskBlockingCollection (.NET 4.0+),如下所示:

BlockingCollection<ProducerTask> buffer = new BlockingCollection<ProducerTask>(1);
// producer task
while(/* lines still available */)
{
    // read 500 lines
    ProducerTask p = new ProducerTask();
    buffer.Add(p); // this will block until the consumer takes the previous task
}
// consumer task
while(/* termination not received */)
{
    ProducerTask p = buffer.Take(); // blocks if no task is available
    // put the lines in the grid
}

更加简单和优雅。

从Tudor非常好的答案中,您还可以查看TPL Dataflow,它为实现生产者 - 消费者模式提供了一组非常干净的构建块。