I have this class (simplified):
// thing.h
#include <mutex>
class Thing
{
public:
void process();
void inner();
private:
std::mutex lock;
};
// thing.cpp
#include "Thing.h"
using namespace std;
void Thing::process()
{
lock_guard<mutex> locking(lock);
inner();
}
void Thing::inner()
{
lock_guard<mutex> locking(lock);
}
If I make a call to process, I get an exception:
Microsoft C++ exception: std::system_error at memory location 0x006FF16C.
Locking on the same lock in the same thread causes this exception. How can I do this without the exception? I thought about adding a flag:
volatile bool alreadyLocked;
Changing inner to:
void Thing::inner()
{
if (!alreadyLocked)
{
lock_guard<mutex> locking(lock);
alreadyLocked = true;
...something magic happens here...
alreadyLocked = false;
}
}
However this feels brittle... is there a right way to do this?
Firstly,
volatilevariables are NOT thread-safe. You must usestd::atomic<T>to have thread-safe variables.volatilehas nothing to do with thread safety.To solve your issue, you can use
std::recursive_mutex, which can be locked/unlocked multiple times from the same thread.From cppreference:
Additionally, please consider refactoring your code so that locking a mutex twice is not required. Improving your design could probably avoid this issue.