在我的项目中,有一个以大约 86 fps 更新的音频线程和一个以 60 fps 运行的图形线程。两个线程都可以产生和使用彼此的值。
但是没有必要消耗每个值,只有最新的值是重要的,并且不需要通知,因为线程只是在需要一个新值时请求一个新值。
在阅读了大量关于线程的网站后,我对我真正需要什么感到有点困惑,因为我的任务很简单。带锁我的代码看起来像:
private T aField; //memory location
//other thread reads value
public void ReadValue(ref T val)
{
lock(myLock) copy aField to val;
}
//this thread updates value
private void UpdateValue(T newVal)
{
lock(myLock) copy newVal to aField;
}
我的第一个问题是,这是否适用于像 float 或 int(<=32 位大小)这样的原始类型而没有任何锁定,因为副本只是一个原子分配?
下一个想法是通过 bool 进行保护:
private T aField; //memory location
private volatile bool isReading;
private volatile bool isWriting;
//other thread reads value
public void ReadValue(ref T val)
{
isReading = true;
if(!isWriting) copy aField to val;
isReading = false;
}
//this thread updates value
private void UpdateValue(T newVal)
{
isWriting = true;
if(!isReading) copy newVal to aField;
isWriting = false;
}
对我来说看起来不错,但我很确定我错过了一些东西。当较快的线程读取而慢速线程想要写入时,我可以想到最坏的情况。然后快速线程将在下一次再次读取旧值,因为没有进行更新。
我还发现了一种非阻塞更新方法,但我想知道它是否以及如何帮助我:
static void LockFreeUpdate<T> (ref T field, Func <T, T> updateFunction)
where T : class
{
var spinWait = new SpinWait();
while (true)
{
T snapshot1 = field;
T calc = updateFunction (snapshot1);
T snapshot2 = Interlocked.CompareExchange (ref field, calc, snapshot1);
if (snapshot1 == snapshot2) return;
spinWait.SpinOnce();
}
}
什么是具有最低延迟的最有效方法?