Why is this an issue?
Mutexes are synchronization primitives that allow to manage concurrency using a mechanism of lock
/unlock
.
While explicitly locking or unlocking a mutex is possible, it is error prone. And this is particularly true in complex code paths (or with
exceptions) where it is easy to have a mismatch between lock
s and unlock
s.
As a result, mutexes should not be locked or unlocked manually.
Adopting the C++ RAII idiom solves this problem by creating an object that will lock the mutex on creation and unlock it on destruction.
Furthermore, using this idiom can also greatly improve the readability of the code.
Several classes are available as RAII wrappers:
-
std::scoped_lock
is the default, most efficient wrapper for simple cases (only available since C++17)
-
std::lock_guard
is similar to std::scoped_lock
, but with less features. It should only be used if you don’t have
access to std::scoped_lock
.
-
std::unique_lock
allows more manual unlocking/locking again, and should only be used when these features are needed, for instance
with condition variables.
Noncompliant code example
#include <mutex>
class DataItem;
class DataStore {
public:
bool store(const DataItem &dataItem);
bool has(const DataItem &dataItem);
};
DataStore sharedDataStore;
std::mutex sharedDataStoreMutex;
bool storeIfRelevantInSharedContext(const DataItem &dataItem) {
sharedDataStoreMutex.lock(); // Noncompliant
if (sharedDataStore.has(dataItem)) {
sharedDataStoreMutex.unlock(); // Noncompliant
return false;
}
bool result = sharedDataStore.store(dataItem);
sharedDataStoreMutex.unlock(); // Noncompliant
return result;
}
Compliant solution
#include <mutex>
class DataItem;
class DataStore {
public:
bool store(const DataItem &dataItem);
bool has(const DataItem &dataItem);
};
DataStore sharedDataStore;
std::mutex sharedDataStoreMutex;
bool storeIfRelevantInSharedContext(const DataItem &dataItem) {
std::scoped_lock<std::mutex> lock(sharedDataStoreMutex);
if (sharedDataStore.has(dataItem)) {
return false;
}
return sharedDataStore.store(dataItem);
}
Resources