I have a program with multiple resources that needs to be lock by their own mutex.
In this program, it might happen that while mutex for resource A is locked, resource A is deleted in another thread.
The following code try to reproduce the logic of what I try to accomplish :
#include <thread>
#include <mutex>
#include <iostream>
#include <map>
int g_i = 0;
struct Resource
{
std::mutex* m_mutex;
};
std::map<unsigned int, Resource> myResources;
std::mutex g_i_mutex; // protects g_i
void shutdown()
{
std::cout << "shutdown -> myMap.size = : " << myResources.size() << std::endl;
std::lock_guard<std::mutex> lock(*myResources[1].m_mutex);
++g_i;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
delete myResources[1].m_mutex;
myResources[1].m_mutex = NULL;
myResources.erase(1);
std::cout << "shutdown -> myMap.size = : " << myResources.size() << std::endl;
std::cout << "shutdown : " << g_i << '\n';
}
void onRecognize()
{
std::cout << "onRecognize -> myMap.size = : " << myResources.size() << std::endl;
std::lock_guard<std::mutex> lock(*myResources[1].m_mutex);
std::cout << "onRecognize -> myMap.size = : " << myResources.size() << std::endl;
++g_i;
std::cout << "onRecognize : " << g_i << '\n';
}
int main()
{
std::cout << __func__ << ": " << g_i << '\n';
Resource myStruct;
myStruct.m_mutex = new std::mutex();
myResources[1] = myStruct;
std::thread t1(shutdown);
std::thread t2(onRecognize);
t1.join();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
t2.join();
std::cout << __func__ << ": " << g_i << '\n';
}
I tried this snippet of code and it works. But I am wondering what happen with lock_guard in onRecognize function, because the mutex is being deleted while he is locked. So, my question might be :
Does deleting a mutex while he is locked somewhere else is dangerous?
Thx
Don't destroy a mutex while it is locked.
The behavior is undefined if the mutex is owned by any thread or if any thread terminates while holding any ownership of the mutex.
http://en.cppreference.com/w/cpp/thread/mutex/~mutex
You have a fundamental concurrency error that renders your code unreliable. The pointer m_mutex
is modified in one thread and used in another, and no synchronization of any kind protects it.
This is catastrophic even if you can't imagine a way it can fail. But it happens to be very easy to imagine ways it can fail. Consider:
onRecognize
evaluates *myResources[1].m_mutex
but hasn't constructed the lock guard yet.shutdown
acquires the lock, destroys the mutex, and returns.onRecognize
tries to construct the lock guard on a lock that no longer exists.So you have bigger problems than anything specific to the semantics of mutexes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With