私のプロジェクトには、約 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();
}
}
待ち時間が最も短く、最も効率的な方法は何ですか?