An example in Meyers' book Effective Modern C ++, paragraph 16.
in caching a class with expensive int evaluation, you can try using the std :: atomic avriables pair instead of the mutex:
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; };
This will work, but sometimes it will work a lot harder than it should. Consumer: the stream calls Widget :: magicValue, sees cacheValid as false, performs two expensive calculations and assigns their sum tocachedValud. At this point, the second thread Widget :: magicValue also sees cacheValid as false and thus carries over from the same expensive calculations as the first thread finished.
Then he gives a solution with a mutex:
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; };
But I think that the solution is not so effective, I believe that to combine a mutex and an atom, it is necessary to create a Double-Checked Locking Pattern , as shown below.
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; };
Because I'm new to multi-threaded programming, so I want to know:
- Is my code correct?
- Is the performance different?
EDIT:
The code is fixed. if (! cachedValue) β if (! cacheValid)