1

在我的项目中,有一个以大约 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();
  }
}

什么是具有最低延迟的最有效方法?

4

1 回答 1

1

对于您的情况,您不需要任何锁,只需将 volatile 添加到 private T aField;防止任何可能的编译器优化

于 2013-10-15T03:16:17.487 回答