我正在尝试在以下代码中锁定我的互斥锁列表,以便只有一个线程可以一次搜索,解锁,锁定或修改它.
#include #include #include #include #include #include #include #include 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 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 guard(map_lock); locklist.insert(std::make_pair(++lock_count, MoveableMutex())); return lock_count; } void Locks::RemoveLock(std::uint32_t ID) { std::lock_guard 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 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 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 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 stop(false); std::atomic 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; }
但是,std::lock_guard在Unlock函数内部,它会导致死锁.如果我从解锁功能中删除lock_guard,它可以正常工作.
std::lock_guard
Unlock
lock_guard没有破坏或解锁的原因吗?
一个线程调用Lock,最终锁定映射中的互斥锁.另一个线程调用Lock,然后锁定map_lock然后尝试锁定地图中的互斥锁,然后卡在那里(map_lock仍然保持).最终,第一个线程退出循环并调用Unlock,等待等待map_lock.
Lock
map_lock
这里的主要设计缺陷是你有一个线程获得两个锁,一个接一个.只有当所有线程以相同的顺序获取它们(并以相反的获取顺序释放)时,这才能安全地工作.但是你的代码在不同的时间以不同的顺序获取它们:这是一个死锁的秘诀.
另请参见:锁定层次结构