peterphonic
peterphonic

Reputation: 1039

Deleting a mutex that is locked

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

Upvotes: 5

Views: 8819

Answers (3)

John Duffy
John Duffy

Reputation: 334

GCC(10.2) & Clang(10) don't have issues with deleting a locked mutex, MSVC 19.28 will terminate.

{
    std::mutex m;
    m.lock();
}//std::terminate() - MSVC

Upvotes: 0

David Schwartz
David Schwartz

Reputation: 182753

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:

  1. onRecognize evaluates *myResources[1].m_mutex but hasn't constructed the lock guard yet.
  2. shutdown acquires the lock, destroys the mutex, and returns.
  3. onRecognize tries to construct the lock guard on a lock that no longer exists.
  4. Boom.

So you have bigger problems than anything specific to the semantics of mutexes.

Upvotes: 4

Brian Bi
Brian Bi

Reputation: 119089

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

Upvotes: 6

Related Questions