英文:
Is there any way I can make my program panic rather than deadlock if I have lock a mutex twice in one thread?
问题
从这篇帖子中,我学到了以下内容:
- 我可以继承自
std::mutex
,然后检查m_holder
是否等于当前线程的ID。我认为这种方法有点取巧,因为继承自std类被认为是一个不好的主意。此外,m_holder
是某个C++库的实现,不是标准接口。 - 我可以使用
unique_lock
的owns_lock
方法。然而,这是一个不好的主意,因为该方法只检查当前锁是否持有互斥量。我们不以这种方式使用unique_lock
。 - 一个
recursive_mutex
可以在线程中多次锁定互斥量时防止死锁。然而,在决定是否真的需要使用它之前,我们必须首先检查我们的代码设计(参考这里)。然而,我认为我有一个很好的设计。我需要的是在某个线程两次锁定某个互斥量时进行运行时检查,它会崩溃而不是死锁。所以recursive_mutex
似乎不适合我。
英文:
From this post, I learned the following:
- I can inherit from
std::mutex
, and check ifm_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 - I can use
owns_lock
ofunique_lock
. However, it is a bad idea, since the method only checks if the current lock holds the mutex. We don't useunique_lock
in this way. - 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 arecursive_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<std::thread::id> 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论