在两个主循环线程之间传递值的非阻塞和低延迟方法

本文关键字:方法 延迟 之间 两个 线程 循环线 循环 | 更新日期: 2023-09-27 18:35:26

在我的项目中,有一个以大约 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 位大小)等原始类型,因为副本只是一个原子赋值?

下一个想法是布尔的保护:

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();
  }
}

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

在两个主循环线程之间传递值的非阻塞和低延迟方法

对于您的情况,您不需要任何锁,只需将易失性添加到私有 T aField; 以防止任何可能的编译器优化