В пункте 16: «Сделать константные функции-члены поточно» есть код следующим образом:Эффективное размещение lock_guard - из пункта 16 из современных эффективных C++
class Widget {
public:
int magicValue() const
{
std::lock_guard<std::mutex> guard(m); // lock m
if (cacheValid) return cachedValue;
else {
auto val1 = expensiveComputation1();
auto val2 = expensiveComputation2();
cachedValue = val1 + val2;
cacheValid = true;
return cachedValue;
}
} // unlock m
private:
mutable std::mutex m;
mutable int cachedValue; // no longer atomic
mutable bool cacheValid{ false }; // no longer atomic
};
Интересно, почему станд :: lock_guard должен быть выполняется всегда на каждом magicValue() вызова, Wouldnt следующие работы, как ожидалось ?:
class Widget {
public:
int magicValue() const
{
if (cacheValid) return cachedValue;
else {
std::lock_guard<std::mutex> guard(m); // lock m
if (cacheValid) return cachedValue;
auto val1 = expensiveComputation1();
auto val2 = expensiveComputation2();
cachedValue = val1 + val2;
cacheValid = true;
return cachedValue;
}
} // unlock m
private:
mutable std::atomic<bool> cacheValid{false};
mutable std::mutex m;
mutable int cachedValue; // no longer atomic
};
Этот способ меньше взаимных блокировок замков потребуется, что делает код более эффективным. Я предполагаю, что атомика всегда быстрее мьютексов.
[править]
Для Комплектность я измерил эффективность обоих apraches, а второй выглядит как только 6% быстрее .: http://coliru.stacked-crooked.com/a/e8ce9c3cfd3a4019
Поскольку чтение cacheValid не может быть атомарным? –
@NeilButterworth: добро пожаловать назад. –
Вы понимаете, что ваши вычисления могут запускаться более одного раза со второй версией – steve