我有一些由多个线程读取和更新的数据。读取和写入都必须是原子的。我正在考虑这样做:
// 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);
}
通过在每次读取和写入时窃取指向它的指针来保护数据,这应该使其成为线程安全的,但每次访问都需要两条互锁指令。将会有大量的读取和写入,我无法提前判断是否会有更多的读取或更多的写入。
能做到比这更有效吗?这在读取时也会锁定,但由于很可能有更多的写入然后读取,因此优化读取没有意义,除非它不会对写入造成惩罚。
我正在考虑在没有互锁指令(以及序列号)的情况下读取指针,复制数据,然后有一种方法来判断序列号是否已更改,在这种情况下它应该重试。不过,这需要一些内存屏障,我不知道它是否可以提高速度。
- - - 编辑 - - -
谢谢大家,很棒的评论!我实际上并没有运行此代码,但我会在今天晚些时候尝试将当前方法与关键部分进行比较(如果我有时间的话)。我仍在寻找最佳解决方案,因此稍后我将返回更高级的评论。再次感谢!