我创建了一个循环缓冲类,需要从两个不同的线程访问它。循环缓冲区使用二维数组,其中一维是行数,另一维是浮点数组的元素(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;
}
}
因此,用户界面线程将每50ms左右检索所有行,而后台TCP服务器将每50 ms左右添加1行。用户界面线程实际上是OpenGL的OnRender回调。我是否会遇到这堂课的问题?如果是这样我该如何避免呢? 谢谢,汤姆
答案 0 :(得分:1)
如果写入发生在GetData()的中间,则总是有可能获得不一致的值。您可能希望使用锁来使Getdata和Adddata操作成为原子以获得一致的值。另外在旁注,它现在可能很好,但是因为它值得一提,它总是很好的使得Get调用异步以避免冻结UI线程,以防它没有立即得到锁。
答案 1 :(得分:1)
它对我来说看起来不安全。 您可能希望尝试这样的事情:
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();
}
}
}
这就是为什么
nextFree
中的线程试图使用AddData
时,没有任何内容阻止从GetData
修改AddData
的不同主题nextFree
并修改Buffer.BlockCopy
,以便applicationWillFinishLaunching
将数据放入错误的索引