2013-12-17 31 views
1

我想在下面的代码中锁定我的互斥列表,以便一次只有一个线程可以搜索,解锁,锁定或修改它。std :: lock_guard不会解锁

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

然而,随着Unlock函数内部std::lock_guard,它会导致死锁。如果我从解锁功能中删除lock_guard,它可以正常工作。

lock_guard没有破坏或解锁的原因吗?

+0

嗯,你总是可以)尝试使用map_lock.lock()/ map_lock.unlock(直接,如果你不相信的std :: lock_guard。但是,看起来你的问题来自其他地方。 – oakad

回答

6

一个线程调用Lock,最终锁定映射中的互斥锁。另一个线程调用Lock,锁住map_lock,然后尝试锁定映射中的互斥锁,并卡在那里(仍保留map_lock)。最终,第一个线程退出循环,并呼叫Unlock,它在map_lock上等待。

这里的主要设计缺陷是你有一个线程获取两个锁,一个接一个。如果所有线程以相同的顺序获取它们(并且按照获取的相反顺序发布),这只能安全工作。但是你的代码在不同的时间以不同的顺序获取它们:这是一个僵局的秘诀。

参见:lock hierarchy

相关问题