gpt4 book ai didi

c++ - C++11中的无锁缓存实现

转载 作者:搜寻专家 更新时间:2023-10-31 02:17:01 24 4
gpt4 key购买 nike

在 C++11 中有没有什么方法可以为一个对象实现无锁缓存,这样可以安全地从多个线程访问?我要缓存的计算不是 super 便宜但也不是 super 昂贵,因此在我的情况下需要锁会破坏缓存的目的。 IIUC, std::atomic不保证无锁。

编辑:因为计算不是太昂贵,我实际上不介意它运行一次或两次太多。但我 - 确实 - 需要确保所有消费者都获得正确的值(value)。在下面的简单示例中,这并不能保证,因为由于内存重新排序,线程可能会获得未初始化的值 m_val。由于另一个线程集 m_alreadyCalculated为真,但没有设置 m_val的值(value)呢。

Edit2:下面的评论指出对于基本类型,std::atomic可能是无锁的。如果是,下面示例中使用 C++11 的内存排序以确保 m_alreadyCalculated 不可能的正确方法是什么?在 m_val 之前设置为真的值设置了吗?

非线程安全缓存示例:

class C {
public:
C(int param) : m_param(param) {}

getValue() {
if (!m_alreadyCalculated) {
m_val = calculate(m_param);
m_alreadyCalculated = true;
}
return m_val;
}

double calculate(int param) {
// Some calculation
}

private:
int m_param;
double m_val;
bool m_alreadyCalculated = false;
}

最佳答案

考虑如下:

class C {
public:
double getValue() {
if (alreadyCalculated == true)
return m_val;

bool expected = false;
if (calculationInProgress.compare_exchange_strong(expected, true)) {
m_val = calculate(m_param);
alreadyCalculated = true;
// calculationInProgress = false;
}
else {
// while (calculationInProgress == true)
while (alreadyCalculated == false)
; // spin
}
return m_val;
}

private:
double m_val;
std::atomic<bool> alreadyCalculated {false};
std::atomic<bool> calculationInProgress {false};
};

其实不是无锁的,里面有一个自旋锁。但我认为如果你不想通过多个线程运行 calculate(),你就无法避免这种锁定。

getValue() 在这里变得更加复杂,但重要的部分是一旦计算出 m_val,它总是会在第一个 if声明。

更新

出于性能原因,将整个类填充到缓存行大小也是一个好主意。

更新 2

原始答案中存在错误,感谢 JVApen 指出这一点(已用评论标记)。变量 calculationInProgress 最好重命名为 calculationHasStarted

另外,请注意,此解决方案假定 calculate() 不会抛出异常。

关于c++ - C++11中的无锁缓存实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36239880/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com