hierarchical_mutex:是否可能出现虚假异常?

pao*_*olo 6 c++ multithreading mutex deadlock

A. Williams在他的《C++ Concurrency in Action》一书中引入了锁层次结构的概念作为死锁避免机制。下面,我报告了一个实现的精简版本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()};
Run Code Online (Sandbox Code Playgroud)

Les 想象线程AB竞争锁定 的实例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();
}
Run Code Online (Sandbox Code Playgroud)

说线程A

  • 来电mutex.lock()
  • 成功评估(1)检查false
  • HierarchicalMutex::Mutex_
  • 更新HierarchicalMutex::current_level并将其设置为1.

此时,线程B

  • 来电mutex.lock()
  • 评估检查(1)true

这意味着线程B将抛出异常;但我希望它等到线程A解锁mutex

我的问题是:

  1. 我想象的执行流程是否可行?
  2. 如果是这样,线程B抛出正确还是应该等待线程A解锁mutex(如我所料)?
  3. 如果我的期望是正确的,应该如何HierarchicalMutex实现才能让线程B等待而不是抛出?替换<=检查是否足够?(1)<

Sam*_*hik 3

此时,线程B:

调用 mutex.lock();

将检查 (1) 评估为 true。

不,不会。current_level被声明为一个thread_local对象。如果您不熟悉这意味着什么,请参阅 C++ 教科书以获取更完整的讨论,但归根结底,current_level每个执行线程中都是一个单独的、离散的对象。在两个执行线程中它都是 0,并且check (1)计算结果为false