在他的书《C++ Concurrency in Action》中,A. Williams介绍了锁层次结构的概念作为避免死锁的机制。以下是一个
HierarchicalMutex
实现(摘自该书)的简化版本:class HierarchicalMutex {
private:
std::mutex Mutex_;
unsigned const Level_;
unsigned PrevLevel_{0};
static thread_local unsigned current_level;
public:
explicit HierarchicalMutex(unsigned level) : Level_{level} {}
void lock() {
if (current_level <= this->Level_) { // (1)
// I can only lock a mutex with a lower level than the currently
// locked one.
throw std::logic_error("lock: Out of order");
}
this->Mutex_.lock();
this->PrevLevel_ = std::exchange(current_level, this->Level_);
}
// try_lock implemented accordingly [...]
void unlock() {
if (current_level != this->Level_)
throw std::logic_error("unlock: Out of order");
current_level = this->PrevLevel_;
this->Mutex_.unlock();
}
};
// current_level initialized to UINT_MAX so that, in the beginning, any
// HierarchicalMutex may be locked.
thread_local unsigned HierarchicalMutex::current_level{
std::numeric_limits<unsigned>::max()};
假设有两个线程A和B竞争锁定一个HierarchicalMutex
实例,如下代码所示:
int main() {
HierarchicalMutex mutex{1};
std::thread threadA{[&mutex] { std::scoped_lock sl{mutex}; }};
std::thread threadB{[&mutex] { std::scoped_lock sl{mutex}; }};
threadB.join();
threadA.join();
}
假设有线程A:
- 调用
mutex.lock()
; - 成功地将检查
(1)
评估为false
; - 锁定
HierarchicalMutex::Mutex_
; - 更新
HierarchicalMutex::current_level
并将其设置为1
。
此时,线程B:
- 调用
mutex.lock()
; - 将检查
(1)
评估为true
。
这意味着线程B将抛出异常;但我希望它等待直到线程A解锁mutex
。
我的问题是:
- 我描绘的执行流程是否可能?
- 如果是的话,线程B抛出异常是否正确,还是应该等待线程A解锁
mutex
(如我所期望的)? - 如果我的期望是正确的,应该如何实现
HierarchicalMutex
,以便线程B等待而不是抛出异常?仅仅将<=
替换为<
就足够了吗?