2013-12-17 58 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

相關問題