删除已锁定的互斥锁

时间:2015-12-01 21:07:57

标签: c++ mutex

我有一个包含多个资源的程序需要由他们自己的互斥锁锁定。

在此程序中,当资源A 的互斥锁被锁定时,可能会发生资源A 在另一个线程中被删除。

以下代码尝试重现我尝试完成的逻辑:

#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';
}

我尝试了这段代码,但它确实有用。但我想知道 on_cognize 函数中 lock_guard 会发生什么,因为互斥锁在被锁定时被删除。所以,我的问题可能是:

在锁定其他地方时删除互斥锁会有危险吗?

THX

3 个答案:

答案 0 :(得分:2)

锁定时不要破坏互斥锁。

  

如果互斥锁由任何线程拥有,或者任何线程在保留互斥锁的所有权时终止,则行为未定义。

http://en.cppreference.com/w/cpp/thread/mutex/~mutex

答案 1 :(得分:1)

您有一个基本的并发错误,导致您的代码不可靠。指针m_mutex在一个线程中被修改并在另一个线程中使用,并且任何类型的同步都不会保护它。

即使你无法想象它会失败的方式,这也是灾难性的。但它恰好很容易想象它可能失败的方式。考虑:

  1. onRecognize评估*myResources[1].m_mutex但尚未构建锁定保护。
  2. shutdown获取锁定,销毁互斥锁​​,然后返回。
  3. onRecognize尝试在不再存在的锁上构建锁定保护。
  4. 动臂。
  5. 因此,除了互斥体的语义之外,你遇到的问题要大于其他任何问题。

答案 2 :(得分:0)

GCC(10.2) 和 Clang(10) 在删除锁定的互斥锁时没有问题,MSVC 19.28 将终止。

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