複数のスレッドによって読み取られ、更新されるデータがいくつかあります。読み取りと書き込みの両方がアトミックである必要があります。私はこのようにすることを考えていました:
// Values must be read and updated atomically
struct SValues
{
double a;
double b;
double c;
double d;
};
class Test
{
public:
Test()
{
m_pValues = &m_values;
}
SValues* LockAndGet()
{
// Spin forver until we got ownership of the pointer
while (true)
{
SValues* pValues = (SValues*)::InterlockedExchange((long*)m_pValues, 0xffffffff);
if (pValues != (SValues*)0xffffffff)
{
return pValues;
}
}
}
void Unlock(SValues* pValues)
{
// Return the pointer so other threads can lock it
::InterlockedExchange((long*)m_pValues, (long)pValues);
}
private:
SValues* m_pValues;
SValues m_values;
};
void TestFunc()
{
Test test;
SValues* pValues = test.LockAndGet();
// Update or read values
test.Unlock(pValues);
}
データは、読み取りと書き込みのたびにデータへのポインタを盗むことで保護されます。これにより、データはスレッドセーフになりますが、アクセスごとに2つのインターロックされた命令が必要です。読み取りと書き込みの両方がたくさんあり、読み取りと書き込みのどちらが増えるかを事前に知ることはできません。
これよりも効果的にできるでしょうか?これは読み取り時にもロックされますが、読み取りよりも書き込みが多い可能性があるため、書き込みにペナルティを課さない限り、読み取りを最適化しても意味がありません。
インターロックされた命令なしで(シーケンス番号とともに)ポインターを取得し、データをコピーしてから、シーケンス番号が変更されたかどうかを確認する方法を考えていました。変更された場合は、再試行する必要があります。ただし、これにはいくつかのメモリバリアが必要であり、速度が向上するかどうかはわかりません。
- - - 編集 - - -
みんなありがとう、素晴らしいコメント!私は実際にこのコードを実行していませんが、現在のメソッドを今日の後半にクリティカルセクションと比較しようとします(時間があれば)。私はまだ最適な解決策を探しているので、後でより高度なコメントに戻ります。再度、感謝します!