简体   繁体   中英

std::lock_guard won't unlock

I'm trying to lock my list of mutexes in the following code so that only one thread can search it, unlock, lock or modify it at a time.

#include <mutex>
#include <map>
#include <memory>
#include <vector>
#include <thread>
#include <atomic>
#include <iostream>
#include <Windows.h>

struct MoveableMutex
{
    std::mutex m;
    MoveableMutex() {}
    MoveableMutex(MoveableMutex const&) {}
    MoveableMutex& operator = (MoveableMutex const&) { return *this; }
};

class Locks
{
    private:
        static std::mutex map_lock;
        static std::uint32_t lock_count;
        std::map<std::uint32_t, MoveableMutex> locklist;

    public:
        std::uint32_t AddLock();
        void RemoveLock(std::uint32_t ID);
        void Lock(std::uint32_t ID);
        bool TryLock(std::uint32_t ID);
        void Unlock(std::uint32_t ID);
};

std::uint32_t Locks::lock_count = 0;
std::mutex Locks::map_lock;

std::uint32_t Locks::AddLock()
{
    std::lock_guard<std::mutex> guard(map_lock);
    locklist.insert(std::make_pair(++lock_count, MoveableMutex()));
    return lock_count;
}

void Locks::RemoveLock(std::uint32_t ID)
{
    std::lock_guard<std::mutex> guard(map_lock);
    auto it = locklist.find(ID);
    if (it != locklist.end())
    {
        it->second.m.unlock();
        locklist.erase(it);
    }
}

void Locks::Lock(std::uint32_t ID)
{
    std::lock_guard<std::mutex> guard(map_lock);
    auto it = this->locklist.find(ID);
    if (it != this->locklist.end())
    {
        it->second.m.lock();
    }
}

bool Locks::TryLock(std::uint32_t ID)
{
    std::lock_guard<std::mutex> guard(map_lock);
    auto it = this->locklist.find(ID);
    if (it != this->locklist.end())
    {
        return it->second.m.try_lock();
    }
    return false;
}

void Locks::Unlock(std::uint32_t ID)
{
    std::lock_guard<std::mutex> guard(map_lock);
    auto it = this->locklist.find(ID);
    if (it != locklist.end())
    {
        it->second.m.unlock();
    }
}

int main()
{
    Locks locklist;
    int i = locklist.AddLock();
    std::atomic<bool> stop(false);
    std::atomic<bool> stop2(false);

    std::thread o([&]
    {
        locklist.Lock(i);
        while(!stop)
        {
            std::cout << "Hey\n";
            Sleep(100);
        }
        locklist.Unlock(i);
    });

    std::thread t([&]
    {
        locklist.Lock(i);
        while(!stop2)
        {
            std::cout << "Hey2\n";
            Sleep(100);
        }
        locklist.Unlock(i);
    });

    Sleep(1000);
    stop = true;
    system("CLS");
    o.join();

    Sleep(1000);
    stop2 = true;
    t.join();
    return 0;
}

However, with the std::lock_guard inside the Unlock function, it causes a deadlock. If I remove the lock_guard from the Unlock function, it works fine.

Is there a reason the lock_guard isn't destructing or unlocking?

One thread calls Lock , which ends up locking the mutex in the map. The other thread calls Lock , which locks map_lock then tries to lock the mutex in the map, and gets stuck there (with map_lock still held). Eventually, the first thread gets out of the loop and calls Unlock , which gets stuck waiting on map_lock .

The main design flaw here is that you have a thread acquire two locks, one after another. This only works safely if all threads acquire them in the same order (and release in reverse order of acquiring). But your code acquires them in different order at different times: that's a recipe for a deadlock.

See also: lock hierarchy

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM