[英]Is my circular buffer threadsafe? If not, how can I make it so?
我创建了一个循环缓冲区类,需要从两个不同的线程访问它。 循环缓冲区使用二维数组,其中一维为行数,另一维为行数数组(其中2048个)的元素。 用户界面线程可以在任何给定时间从数组读取所有行。 后台线程是一个TCP服务器线程,它检索需要在此数组中插入的2048个浮点数。 这是代码
static class CircularArrayBuffer
{
static float[,] buffer;
static int columns, rows;
static int nextFree = 0;
public static void CreateBuffer(int _columns, int _rows)
{
columns = _columns;
rows = _rows;
buffer = new float[rows,columns];
nextFree = 0; //reset pointer to first free buffer
}
public static float[] GetData(int index)
{
if (index > rows)
{
throw new System.ArgumentException("Index cannot be more than rows", "index");
}
float[] rowArray = new float[columns];
Buffer.BlockCopy(buffer, (((nextFree - 1 + index) % rows) * 4 * columns), rowArray, 0, columns * 4); //takes 2 microseconds!
return rowArray;
}
public static void AddData(float[] rowArray) //number of columns must be set!
{
if (rowArray.Count() > columns)
{
throw new System.ArgumentException("Data length cannot be more than number of columns", "columns");
}
Buffer.BlockCopy(rowArray, 0, buffer, nextFree * 4 * columns, columns * 4);
nextFree = (nextFree + 1) % rows;
}
}
因此,用户界面线程将每隔50毫秒左右检索一次所有行,而后台TCP服务器将每隔50毫秒左右检索一次行。 用户界面线程实际上是OpenGL的OnRender回调。 我会在这堂课上遇到问题吗? 如果可以,我该如何避免呢? 谢谢汤姆
如果写入发生在GetData()的中间,则总是有可能获得不一致的值。 您可能希望使用锁来使Getdata和Adddata操作原子化以获得一致的值。 还要注意,它现在可能还不错,但是由于值得一提,使Get调用异步以避免在不立即获得锁的情况下冻结UI线程始终是一件好事。
对我来说,它看起来并不安全。 您不妨尝试这样的方法:
static class CircularArrayBuffer
{
static float[,] buffer;
static int columns, rows;
static int nextFree = 0;
static readonly ReaderWriterLockSlim rwLockSlim = new ReaderWriterLockSlim();
public static void CreateBuffer(int _columns, int _rows)
{
columns = _columns;
rows = _rows;
buffer = new float[rows, columns];
nextFree = 0; //reset pointer to first free buffer
}
public static float[] GetData(int index)
{
try
{
rwLockSlim.EnterReadLock();
if (index > rows)
{
throw new System.ArgumentException("Index cannot be more than rows", "index");
}
float[] rowArray = new float[columns];
Buffer.BlockCopy(buffer, (((nextFree - 1 + index) % rows) * 4 * columns), rowArray, 0, columns * 4); //takes 2 microseconds!
}
catch(Exception ex)
{
//handle the exception nicely
}
finally
{
rwLockSlim.ExitReadLock();
}
return rowArray;
}
public static void AddData(float[] rowArray) //number of columns must be set!
{
try
{
rwLockSlim.EnterWriteLock();
if (rowArray.Count() > columns)
{
throw new System.ArgumentException("Data length cannot be more than number of columns", "columns");
}
Buffer.BlockCopy(rowArray, 0, buffer, nextFree * 4 * columns, columns * 4);
nextFree = (nextFree + 1) % rows;
}
catch(Exception ex)
{
//handle the exception nicely
}
finally
{
rwLockSlim.ExitWriteLock();
}
}
}
这就是为什么
AddData
修改nextFree
同时GetData
线程试图使用它 AddData
并修改nextFree
因此Buffer.BlockCopy
会将数据放置在错误的索引处
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.