Meyers 的《Effective Modern C++ 》一书中的一个例子,第 16 条。
在缓存计算成本高的 int 的类中,您可能会尝试使用一对 std::atomic 可变量而不是互斥锁:
class Widget {
public:
int magicValue() const {
if (cachedValid) {
return cachedValue;
} else {
auto val1 = expensiveComputation1();
auto val2 = expensiveComputation2();
cachedValue = va1 + val2;
cacheValid = true;
return cachedValue;
}
}
private:
mutable std::atomic<bool> cacheValid { false };
mutable std::atomic<int> cachedValue;
};
这会起作用,但有时它会比应有的工作更难。考虑:一个线程调用 Widget::magicValue,将 cacheValid 视为 false,执行两个昂贵的计算,并将它们的总和分配给 cachedValud。此时,第二个线程调用 Widget::magicValue,也将 cacheValid 视为 false,因此执行与第一个线程刚刚完成的相同的昂贵计算。
然后他给出了一个互斥锁的解决方案:
class Widget {
public:
int magicValue() const {
std::lock_guard<std::mutex> guard(m);
if (cacheValid) {
return cachedValue;
} else {
auto val1 = expensiveComputation1();
auto val2 = expensiveComputation2();
cachedValue = va1 + val2;
cacheValid = true;
return cachedValue;
}
}
private:
mutable std::mutex m;
mutable bool cacheValid { false };
mutable int cachedValue;
};
但我认为解决方案不是那么有效,我考虑将互斥锁和原子结合起来组成一个双重检查锁定模式,如下所示。
class Widget {
public:
int magicValue() const {
if (!cacheValid) {
std::lock_guard<std::mutex> guard(m);
if (!cacheValid) {
auto val1 = expensiveComputation1();
auto val2 = expensiveComputation2();
cachedValue = va1 + val2;
cacheValid = true;
}
}
return cachedValue;
}
private:
mutable std::mutex m;
mutable std::atomic<bool> cacheValid { false };
mutable std::atomic<int> cachedValue;
};
因为我是多线程编程的新手,所以想了解一下:</p>
- 我的代码对吗?
- 它的性能更好吗?
编辑:
修复了代码。if (!cachedValue) -> if (!cacheValid)