65.9K
CodeProject 正在变化。 阅读更多。
Home

循环缓冲区

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (18投票s)

2002年9月12日

3分钟阅读

viewsIcon

248720

downloadIcon

10318

C# 中循环缓冲区的实现。

循环缓冲区用于两个进程之间的数据传输。生产者进程将项目放入循环缓冲区,而消费者进程将它们移除。循环缓冲区的可变容量适应生产者和消费者进程之间的时间差异。

循环缓冲区比其他保存可变数量数据的队列执行得更快,因为固定大小的内存块只需从内存管理中分配一次,然后重复使用(循环缓冲区可以被可视化为这样,但实际上是一个线性缓冲区,其索引在到达缓冲区末尾时会环绕,对缓冲区大小取模)。

通常,循环缓冲区用于解耦以不同速度运行的两个进程。例如,一个更快的生产者进程可以将数据“爆发式”地放入缓冲区,并继续其处理。然后,较慢的消费者可以按照自己的速率读取这些数据,而无需同步和减慢生产者。在这种类型的应用程序中,从长远来看,两个进程的平均速率必须相同,以避免循环缓冲区的溢出或下溢情况(这是“同步模式”的操作)。此外,排序至关重要。除非使用下面描述的同步方法之一,否则生产者进程必须始终首先执行。

在其他类型的应用程序中,循环缓冲区的溢出和随之而来的数据丢失是可以接受的。例如 - 错误日志记录。在这里,进程状态数据以高速度连续写入循环缓冲区,但只有最后几个记录的项目对于解决可能需要数小时或数天才能重复的问题有用。大小为 N 的缓冲区被生产者写入的最后 N-1 个项目饱和,并在检测到错误情况时读取。这是循环缓冲区的“异步模式”。

在同步模式下,有两种方法可用于确保不会丢失数据。阻塞方法和水位线方法。

调用阻塞方法将导致调用线程阻塞,直到循环缓冲区具有请求数量的项目。请注意,必须使用阻塞对。也就是说,如果使用了DequeueBlockingCopyToBlocking方法,则还必须使用EnqueueBlocking方法。当循环缓冲区中的项目数量达到预设水平时,WaterMark方法将触发一个事件 - 从而消除了由于进程阻塞而浪费的处理时间。用法示例

theCB.SetWaterMark(8); // notify everytime cb has 8 items 
theCB.WaterMarkNotify += new QueueCB.CBEventHandler(WaterMarkEvent);

我提供的 Winform 应用程序对于使用循环缓冲区构建系统并不是非常有用。我用它来测试该类,然后为了好玩添加了 GUI。但如果您不熟悉这些概念,它可能是一个有用的学习工具。它模拟了一个 N=36 大小的带有生产者和消费者线程的循环缓冲区。它的运行方式有点像时钟。

Sample Image

支持IEnumerator 接口,可以使用foreach()从循环缓冲区读取项目。

DLL 已签名,可以在 GAC 中安装。

在多线程应用程序中使用循环缓冲区非常复杂,并且容易出现可能的时间风险。这是 1.0.0.0 版本,所以请小心!

小心阻塞方法,在最后一刻我决定使用一个AutoResetEvent进行同步,因为我想学习如何使用它。但就测试的程度而言,一切似乎都有效。请向我报告错误(以及修复方案?)。

感谢 .NET 团队为我们提供了如此惊人的技术,并使这些东西如此有趣。

© . All rights reserved.