有没有办法让我的程序在一个线程中两次锁定互斥锁而不是死锁?

huangapple go评论64阅读模式
英文:

Is there any way I can make my program panic rather than deadlock if I have lock a mutex twice in one thread?

问题

这篇帖子中,我学到了以下内容:

  1. 我可以继承自std::mutex,然后检查m_holder是否等于当前线程的ID。我认为这种方法有点取巧,因为继承自std类被认为是一个不好的主意。此外,m_holder是某个C++库的实现,不是标准接口。
  2. 我可以使用unique_lockowns_lock方法。然而,这是一个不好的主意,因为该方法只检查当前锁是否持有互斥量。我们不以这种方式使用unique_lock
  3. 一个recursive_mutex可以在线程中多次锁定互斥量时防止死锁。然而,在决定是否真的需要使用它之前,我们必须首先检查我们的代码设计(参考这里)。然而,我认为我有一个很好的设计。我需要的是在某个线程两次锁定某个互斥量时进行运行时检查,它会崩溃而不是死锁。所以recursive_mutex似乎不适合我。
英文:

From this post, I learned the following:

  1. I can inherit from std::mutex, and check if m_holder equals to the current thread id. I think the way is kind of hack, since it is considered a bad idea to inherit from std class. Moreover, m_holder is some implementation of some C++ library which is not a standard interface
  2. I can use owns_lock of unique_lock. However, it is a bad idea, since the method only checks if the current lock holds the mutex. We don't use unique_lock in this way.
  3. A recursive_mutex can save us from deadlock when we double lock a mutex in a thread. However, we must firstly check our code design before we decide that we really need to use this. However, I think I have a good design. What I need is a runtime check that if a certain mutex is locked twice by a thread, it will crash rather than dead lock. So a recursive_mutex seems not suitable for me.

答案1

得分: 1

以下是要翻译的内容:

有多种方法可以通过第一种解决方案既保留蛋糕又吃掉它。
如果我们将std::mutex包装为成员而不是继承它,我们可以完全达到相同的结果:

class mutex
{
    std::mutex m_mutex;
    std::atomic<std::thread::id> m_holder = std::thread::id{};

public:
    void lock()
    {
        // TODO: 如果需要,我们可以检查locked_by_caller()
        //       如果为真,则触发异常
        m_mutex.lock();
        m_holder = std::this_thread::get_id();
    }

    bool try_lock()
    {
        if (m_mutex.try_lock()) {
            m_holder = std::this_thread::get_id();
            return true;
        }
        return false;
    }

    void unlock()
    {
        m_mutex.unlock();
    }

    bool locked_by_caller() const
    {
        return m_holder == std::this_thread::get_id();
    }
};

原始代码由@AmiTavory提供,链接:https://stackoverflow.com/a/30109512/5740428

此外,m_holder 是某个 C++ 库的实现,不是标准接口

不,您误解了原始代码。m_holder 是我们自己定义的成员。我们不依赖于任何特定的标准库实现。通常,标准库成员的命名方式类似于_M_holder,以使用不能被宏替换的保留名称。

英文:

There are ways to have your cake and eat it with the first solution.
We could achieve exactly the same result if we wrapped the std::mutex as a member instead of inheriting from it:

class mutex
{
    std::mutex m_mutex;
    std::atomic&lt;std::thread::id&gt; m_holder = std::thread::id{};

public:
    void lock()
    {
        // TODO: if we wanted to, we could check locked_by_caller()
        //       and panic if true
        m_mutex.lock();
        m_holder = std::this_thread::get_id(); 
    }
    
    bool try_lock()
    {
        if (m_mutex.try_lock()) {
            m_holder = std::this_thread::get_id();
            return true;
        }
        return false;
    }

    void unlock()
    {
        m_mutex.unlock();
    }

    bool locked_by_caller() const
    {
        return m_holder == std::this_thread::get_id();
    }
};

Original code provided by @AmiTavory at https://stackoverflow.com/a/30109512/5740428

> Moreover, m_holder is some implementation of some C++ library which is not a standard interface

No, you've misunderstood the original code. m_holder is a member we defined ourselves. We're not relying on any particular standard library implementation. In general, standard library members are named something like _M_holder to use reserved names which can't be replaced by macros.

huangapple
  • 本文由 发表于 2023年6月16日 00:18:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76483655.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定