using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
/**
* 缓冲区的可能状态:
* <code>
* (1)
* ----====== data ======-----rspace----
* | | |
* rd_nxt wr_nxt capacity-1
* (2)
* ==ldata==-------------==== rdata ====
* | | |
* wr_nxt rd_nxt capacity-1
* (3)
* ===ldata=============rdata===========(full of data)
* |
* wr_nxt(rd_nxt)
* (4)
* -------------------------------------(empty)
* |
* wr_nxt(rd_nxt)
* </code>
*/
/// <summary>
/// 使用字节数组来实现的缓冲区. 该缓冲区把该数组看作是一个环,
/// 支持在一块固定的数组上的无限次读和写, 数组的大小不会自动变化.
/// ideawu
/// </summary>
/// <typeparam name="T">所缓冲的数据类型.</typeparam>
public class ArrayBuffer<T>
{
/// <summary>
/// 默认大小.
/// </summary>
private const int DFLT_SIZE = 512 * 1024;
/// <summary>
/// 缓冲区还能容纳的元素数目.
/// </summary>
private int space = 0;
/// <summary>
/// 缓冲区中的数据元素数目.
/// </summary>
private int available = 0;
/// <summary>
/// 缓冲区的容量.
/// </summary>
private int capacity = DFLT_SIZE;
// 注意 capacity 和 buf.Length 可以不相同, 前者小于或者等于后者.
/// <summary>
/// 下一次要将数据写入缓冲区的开始下标.
/// </summary>
private int wr_nxt = 0;
/// <summary>
/// 下一次读取接收缓冲区的开始下标.
/// </summary>
private int rd_nxt = 0;
private int readTimeout = -1;
private int writeTimeout = -1;
private Semaphore writeSemaphore = new Semaphore(1, 1);
/// <summary>
/// 缓冲区所使用的数组.
/// </summary>
private T[] dataBuf;
private object bufLock = new object();
/// <summary>
/// 如果当前缓冲区中有数据可读, 它将会被设置.
/// </summary>
private Semaphore readSemaphore = new Semaphore(0, 1);
/// <summary>
/// 创建一个具体默认容量的缓冲区.
/// </summary>
public ArrayBuffer()
: this(DFLT_SIZE) {
}
/// <summary>
/// 创建一个指定容量的缓冲区.
/// </summary>
/// <param name="capacity">缓冲区的容量.</param>
public ArrayBuffer(int capacity)
: this(new T[capacity]) {
}
/// <summary>
/// 使用指定的数组来创建一个缓冲区.
/// </summary>
/// <param name="buf">缓冲区将要使用的数组.</param>
public ArrayBuffer(T[] buf)
: this(buf, 0, 0) {
}
/// <summary>
/// 使用指定的数组来创建一个缓冲区, 且该数组已经包含数据.
/// </summary>
/// <param name="buf">缓冲区将要使用的数组.</param>
/// <param name="offset">数据在数组中的偏移.</param>
/// <param name="size">数据的字节数.</param>
public ArrayBuffer(T[] buf, int offset, int size) {
this.dataBuf = buf;
capacity = buf.Length;
available = size;
space = capacity - available;
rd_nxt = offset;
wr_nxt = offset + size;
}
/// <summary>
/// 缓冲区还能容纳的元素数目.
/// </summary>
public int Space {
get {
return space;
}
}
/// <summary>
/// 缓冲区中可供读取的数据的元素数目
/// </summary>
public int Available {
get {
return available;
}
}
/// <summary>
/// get, set 接收缓冲区的大小(元素数目). 默认值为 512K.
/// Capacity 不能设置为小于 Available 的值(实现会忽略这样的值).
/// </summary>
public int Capacity {
get {
return capacity;
}
set {
lock (bufLock) {
if (value < available || value == 0) {
return;
//throw new ApplicationException("Capacity must be larger than Available.");
}
if (value == capacity) {
return;
}
if (value > capacity && space ==0) {
// 可写空间变为非空, 释放可写信号.
writeSemaphore.Release();
}
T[] buf = new T[value];
if (available > 0) {
available = ReadData(buf, 0, buf.Length);
// 下面的用法是错误的!
//available = Read(buf, 0, buf.Length);
}
dataBuf = buf;
capacity = value;
space = capacity - available;
rd_nxt = 0;
// 当容量缩小时, 可能导致变化后可写空间为0, 这时wr_nxt=0.
wr_nxt = (space == 0) ? 0 : available;
}
}
}
/// <summary>
/// Read 方法的超时时间(单位毫秒). 默认为 -1, 表示无限长.
/// </summary>
public int ReadTimeout {
get {
return readTimeout;
}
set {
readTimeout = value;
}
}
/// <summary>
/// Write 方法的超时时间(单位毫秒). 默认为 -1, 表示无限长.
/// </summary>
public int WriteTimeout {
get {
return writeTimeout;
}
set {
writeTimeout = value;
}
}
/// <summary>
/// 清空本缓冲区.
/// </summary>
public void Clear() {
lock (bufLock) {
available = 0;
space = capacity;
rd_nxt = 0;
wr_nxt = 0;
}
}
/*
/// <summary>
/// 将读指针向前移动 num 个单元. 如果 num 大于 Avalable,
/// 将抛出异常.
/// </summary>
/// <param name="num">读指针要向前的单元个数.</param>
/// <exception cref="ApplicationException">num 大于 Avalable.</exception>
public void Seek(int num) {
}
*/
/// <summary>
/// 未实现.
/// </summary>
/// <returns></returns>
public T ReadOne() {
throw new Exception("Not supported.");
}
/// <summary>
/// 从缓冲区中读取数据. 读取的字节数一定是 buf.Length 和 Available 的较小者.
/// </summary>
/// <param name="buf">存储接收到的数据的缓冲区.</param>
/// <returns>已经读取的字节数. 一定是 size 和 Available 的较小者.</returns>
public int Read(T[] buf) {
return Read(buf, 0, buf.Length);
}
/// <summary>
/// 从缓冲区中读取数据. 读取的字节数一定是 size 和 Available 的较小者.
/// 本方法是线程安全的.
/// </summary>
/// <param name="buf">存储接收到的数据的缓冲区.</param>
/// <param name="offset">buf 中存储所接收数据的位置.</param>
/// <param name="size">要读取的字节数.</param>
/// <returns>已经读取的字节数. 一定是 size 和 Available 的较小者.</returns>
public int Read(T[] buf, int offset, int size) {
if (!readSemaphore.WaitOne(readTimeout, false)) {
throw new ApplicationException("Read timeout.");
}
lock (bufLock) {
int nread = ReadData(buf, offset, size);
if (space == 0) {
// 释放可写信号.
writeSemaphore.Release();
}
space += nread;
available -= nread;
if (available > 0) {
// 释放一个信号, 以便下一次再读.
readSemaphore.Release();
}
return nread;
}
}
/// <summary>
/// 把本缓冲区的数据复制指定的数组中, 并移动读指针.
/// </summary>
private int ReadData(T[] buf, int offset, int size) {
int nread = (available >= size) ? size : available;
// 当 rd_nxt 在 wr_nxt 的左边时, 缓冲的右边包含的网络字节数.
int rdata = capacity - rd_nxt;
if (rd_nxt < wr_nxt || rdata >= nread/*隐含rd_nxt >= wr_nxt*/) {
Array.Copy(dataBuf, rd_nxt, buf, offset, nread);
rd_nxt += nread;
} else {
// 两次拷贝.
Array.Copy(dataBuf, rd_nxt, buf, offset, rdata);
rd_nxt = nread - rdata;
Array.Copy(dataBuf, 0, buf, offset + rdata, rd_nxt);
}
return nread;
}
/// <summary>
/// 写入数据到缓冲区.
/// </summary>
/// <param name="buf">要写入的数据的缓冲区.</param>
public void Write(byte[] buf) {
Write(buf, 0, buf.Length);
}
/// <summary>
/// 写入数据到缓冲区. 注意: 本方法不是线程安全的.
/// </summary>
/// <param name="buf">要写入的数据的缓冲区.</param>
/// <param name="offset">数据缓冲区中要写入数据的起始位置.</param>
/// <param name="size">要写入的字节数.</param>
/// <exception cref="ApplicationException">如果空间不足, 会抛出异常.</exception>
public void Write(byte[] buf, int offset, int size) {
int n_left = size;
int n_offset = offset;
int nwrite;
int rspace;
while (n_left > 0) {
// 这样的超时控制并不准确!
if (!writeSemaphore.WaitOne(writeTimeout, false)) {
throw new ApplicationException("Write timeout.");
}
lock (bufLock) {
nwrite = (space >= n_left) ? n_left : space;
// 当 rd_nxt 在 wr_nxt 的左边时, 缓冲的右边可以放置的网络字节数.
rspace = capacity - wr_nxt;
if (wr_nxt < rd_nxt || rspace >= nwrite/*隐含wr_nxt >= rd_nxt*/) {
Array.Copy(buf, n_offset, dataBuf, wr_nxt, nwrite);
wr_nxt += nwrite;
if (wr_nxt == capacity) {
wr_nxt = 0;
}
} else {
// 两次拷贝.
Array.Copy(buf, n_offset, dataBuf, wr_nxt, rspace);
wr_nxt = nwrite - rspace; // 是调用下一句之后的 wr_nxt值.
Array.Copy(buf, n_offset + rspace, dataBuf, 0, wr_nxt);
}
if (available == 0) {
readSemaphore.Release();
}
space -= nwrite;
available += nwrite;
if (space > 0) {
// 释放可写信号.
writeSemaphore.Release();
}
n_offset += nwrite;
n_left -= nwrite;
}
} // end while
/* 不需要 WriteTimeout 的版本.
// 和 Read 是对称的.
lock (bufLock) {
if (space < size) {
// TBD: 是否实现写超时机制?
throw new ApplicationException("Not enough space.");
}
// 当 wr_nxt 在 rd_nxt 的左边时, 缓冲的右边可以放置的网络字节数.
int rspace = capacity - wr_nxt;
if (wr_nxt < rd_nxt || rspace >= size) {
Array.Copy(buf, offset, dataBuf, wr_nxt, size);
wr_nxt += size;
} else {
// 两次拷贝.
Array.Copy(buf, offset, dataBuf, wr_nxt, rspace);
wr_nxt = size - rspace;
Array.Copy(buf, offset + rspace, dataBuf, 0, wr_nxt);
}
if (available == 0) {
readSemaphore.Release();
}
space -= size;
available += size;
}
*/
}
}
分享到:
相关推荐
在这个“C#缓冲区分析代码”中,我们可以深入理解如何在C#中有效地利用缓冲区进行数据操作。 首先,我们要知道缓冲区的基本原理。缓冲区是一个临时存储区域,用于存放数据,以减少频繁的数据读写操作,提高系统效率...
ArcEngine+C#缓冲区分析(GP工具+ITopologicalOperator接口两种方法实现) GP工具为打开窗口,ITopologicalOperator接口代码设置参数直接点击地图实现缓冲分析
本主题将深入探讨如何结合ArcEngine和C#语言来实现缓冲区分析,这对于理解和应用地理空间数据至关重要。 缓冲区分析是GIS中的一个基础操作,它用于创建围绕特定地理特征(如点、线或面)的区域,这些区域的距离按照...
在C#编程环境下,我们经常需要处理与图形、空间数据相关的任务,这时缓冲区就显得至关重要。本教程将深入探讨如何在C#中创建和查询点、线、面的缓冲区,以及它们在实际应用中的意义。 首先,让我们了解什么是缓冲区...
在VS2008中以c#语言写的 动画演示: 面内缓冲区
总的来说,理解并实现点和线多边形缓冲区的C#算法需要掌握基本的GIS概念、C#编程技巧以及相关的GIS库。通过这个项目,你可以深入学习如何在Web环境中进行空间数据的处理和展示,这对于地理信息系统的开发和数据分析...
在VS2008中以c#语言写的 动画演示: 面外缓冲区
在C#中,我们可以通过双缓冲技术来有效地解决这个问题,提高用户体验。下面将详细讲解C#中如何实现双缓冲以及其工作原理。 双缓冲是一种图形渲染技术,它通过在内存中创建一个临时的缓冲区来存储图形信息,然后再一...
在C#编程中,动画缓冲加载和进度显示是提高用户体验的关键技术。这主要涉及到Windows Forms或WPF应用程序中用户界面(UI)的优化,尤其是在处理大量数据或执行长时间操作时。下面将详细介绍这些知识点。 首先,动画...
C#双缓冲技术是一种用于图形界面编程中减少或消除绘制过程中出现闪烁现象的技术。在处理图形绘制时,特别是在绘图区域频繁更新或绘制复杂图形时,绘制操作往往会导致用户界面出现闪烁。这种闪烁是由于在绘图过程中,...
### WinCE C# 双缓冲技术详解 #### 一、双缓冲技术介绍 在图形界面设计与开发领域,为了提高用户界面(UI)的流畅度并减少闪烁问题,双缓冲技术成为一种常用的优化手段。本篇文章将围绕WinCE平台下的C#双缓冲技术...
在C#编程中,双缓冲技术是一种用于优化图形绘制,特别是动画效果的策略。它能够有效地减少屏幕闪烁和图像撕裂,提供更加平滑、无干扰的视觉体验。双缓冲的核心概念是使用两个图像缓冲区(通常称为帧缓冲区)来处理...
本话题将深入探讨环形缓冲区的概念、设计原理以及如何在C#中实现它。 环形缓冲区,也称为循环缓冲区,是基于数组的一种线性缓冲区。它的主要特点是其首尾相连,形成一个闭合的环状结构,使得数据可以像在环上移动...
在计算机科学中,缓冲区(Buffer)是一种存储数据的临时区域,它在处理大量数据时起着关键作用。缓冲区分析则是对这些存储区域进行操作和优化的过程,以提高程序性能,减少I/O操作,以及确保数据处理的高效性和正确...
本话题主要关注C#语言实现点和线的缓冲区生成算法。 点缓冲区生成相对简单,因为一个点的缓冲区本质上是一个圆。在C#中,可以使用`System.Drawing`或`System.Windows.Shapes`命名空间中的图形类来绘制圆,通过设定...
C#绘图双缓冲技术总结 双缓冲技术是C#绘图中的一种常用技术,用于解决绘图窗口闪烁问题。.NET Framework 1.1 和 .NET 2.0 中的双缓冲技术有所不同。在 .NET 1.1 中,使用 `this.SetStyle(ControlStyles....
### ArcEngine 缓冲区分析代码详解 #### 引言 缓冲区分析是地理信息系统(GIS)中的一个重要功能,主要用于创建一个围绕特定地理要素(如点、线或多边形)的区域,该区域内的所有对象均处于指定的距离范围内。本文...
"C#版服务端双缓冲队列"就是一种为了解决此类问题而设计的数据结构。这个概念基于“空间换时间”的策略,即通过额外的空间来减少处理时间,以提升程序的执行效率。本文将详细讲解双缓冲队列的概念、实现原理以及它在...
ArcEngine作为Esri公司提供的强大的地图和地理信息系统(GIS)开发平台,为开发者提供了丰富的API和工具,使得开发者可以利用C#等编程语言进行二次开发,构建定制化的GIS应用。本系统充分利用了ArcEngine的功能,...