关于线程安全非阻塞缓冲区管理器的建议
我创建了一个简单的缓冲区管理器类,用于异步套接字。这将防止内存碎片并提高性能。对于进一步改进或其他方法有什么建议吗?
public class BufferManager
{
private int[] free;
private byte[] buffer;
private readonly int blocksize;
public BufferManager(int count, int blocksize)
{
buffer = new byte[count * blocksize];
free = new int[count];
this.blocksize = blocksize;
for (int i = 0; i < count; i++)
free[i] = 1;
}
public void SetBuffer(SocketAsyncEventArgs args)
{
for (int i = 0; i < free.Length; i++)
{
if (1 == Interlocked.CompareExchange(ref free[i], 0, 1))
{
args.SetBuffer(buffer, i * blocksize, blocksize);
return;
}
}
args.SetBuffer(new byte[blocksize], 0, blocksize);
}
public void FreeBuffer(SocketAsyncEventArgs args)
{
int offset = args.Offset;
byte[] buff = args.Buffer;
args.SetBuffer(null, 0, 0);
if (buffer == buff)
free[offset / blocksize] = 1;
}
}
I've created a simple buffer manager class to be used with asyncroneous sockets. This will protect against memory fragmentation and improve performance. Any suggestions for further improvements or other approaches?
public class BufferManager
{
private int[] free;
private byte[] buffer;
private readonly int blocksize;
public BufferManager(int count, int blocksize)
{
buffer = new byte[count * blocksize];
free = new int[count];
this.blocksize = blocksize;
for (int i = 0; i < count; i++)
free[i] = 1;
}
public void SetBuffer(SocketAsyncEventArgs args)
{
for (int i = 0; i < free.Length; i++)
{
if (1 == Interlocked.CompareExchange(ref free[i], 0, 1))
{
args.SetBuffer(buffer, i * blocksize, blocksize);
return;
}
}
args.SetBuffer(new byte[blocksize], 0, blocksize);
}
public void FreeBuffer(SocketAsyncEventArgs args)
{
int offset = args.Offset;
byte[] buff = args.Buffer;
args.SetBuffer(null, 0, 0);
if (buffer == buff)
free[offset / blocksize] = 1;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编辑:
下面的原始答案解决了耦合过紧的代码构造问题。然而,从整体上考虑解决方案,我会避免仅使用一个大缓冲区并以这种方式移交其中的片段。您将代码暴露于缓冲区溢出(我们可以将其称为缓冲区“欠载”问题)。相反,我会管理一个字节数组数组,每个字节数组都是一个离散的缓冲区。移交的偏移量始终为 0,大小始终为缓冲区的长度。任何试图读取/写入超出边界的部分的不良代码都将被捕获。
原始答案
您已将该类耦合到 SocketAsyncEventArgs,实际上它需要的只是一个分配缓冲区的函数,将 SetBuffer 更改为:-
现在您可以从使用代码中调用类似这样的代码:-
I'在这种情况下,我不确定类型推断是否足够聪明来解析 buf、offset、size 的类型。如果不是,您将必须将类型放在参数列表中:-
但是现在您的类可用于为各种要求分配缓冲区,这些要求也使用非常常见的 byte[]、int、int 模式。
当然,您需要将自由操作解耦到以下位置:-
在 SocketAsyncEventArgs 的情况下,这要求您在使用代码中对 EventArgs 调用 SetBuffer。如果您担心此方法会降低释放缓冲区并将其从套接字使用中删除的原子性,请对此调整后的缓冲区管理器进行子类化,并在子类中包含 SocketAsyncEventArgs 特定代码。
Edit:
The orignal answer below addresses a code construction issue of overly tight coupling. However, considering the solution as whole I would avoid using just one large buffer and handing over slices of it in this way. You expose your code to buffer overrun (and shall we call it buffer "underrun" issues). Instead I would manage an array of byte arrays each being a discrete buffer. Offset handed over is always 0 and size is always the length of the buffer. Any bad code that attempts to read/write parts beyond the boundaries will be caught.
Original answer
You've coupled the class to SocketAsyncEventArgs where in fact all it needs is a function to assign the buffer, change SetBuffer to:-
Now you can call from consuming code something like this:-
I'm not sure that type inference is clever enough to resolve the types of
buf, offset, size
in this case. If not you will have to place the types in the argument list:-However now your class can be used to allocate a buffer for all manner of requirements that also use the byte[], int, int pattern which is very common.
Of course you need to decouple the free operation to but thats:-
This requires you to call SetBuffer on the EventArgs in consuming code in the case for
SocketAsyncEventArgs
. If you are concerned that this approach reduces the atomicity of freeing the buffer and removing it from the sockets use, then sub-class this adjusted buffer manager and includeSocketAsyncEventArgs
specific code in the sub-class.我用完全不同的方法创建了一个新类。
我有一个接收字节数组的服务器类。然后,它将调用不同的委托,将缓冲区对象交给它们,以便其他类可以处理它们。当这些类完成后,他们需要一种方法将缓冲区推回堆栈。
I've created a new class with a completely different approach.
I have a server class that receives byte arrays. It will then invoke different delegates handing them the buffer objects so that other classes can process them. When those classes are done they need a way to push the buffers back to the stack.