如何解决 C++ 中的未释放锁问题

Posted

技术标签:

【中文标题】如何解决 C++ 中的未释放锁问题【英文标题】:How to solve unreleased lock issue in C++ 【发布时间】:2013-07-20 01:54:07 【问题描述】:

如果可能的话,请有人通过参考或示例帮助我解决 C++ 中的死锁问题。

场景如下。

线程1被互斥锁锁定并做一些操作,线程2和线程3处于等待线程1解锁访问资源的状态。

发生了一些中止/意外的事情——线程 1 被终止并且没有获得解锁,线程 2 和线程 3 仍在等待。

在这种情况下如何保存主线程(意味着主线程应该不会发生任何事情)。

请说明如何在 c++ 中解决此类问题。

谢谢, 酋长

【问题讨论】:

你能展示一些代码来说明你是如何在 c++ 中使用线程的吗? “保存主线程”是什么意思?展示一个小的、可编译的代码示例将非常有帮助 为什么投反对票?这是一个有价值且严肃的问题(可能超出了反对者的概念)! 这不是死锁。死锁是一个循环的锁链。这只是一个未释放的锁,即锁泄漏。解决方案与任何其他资源泄漏相同。 修复线程 1 怎么样? 【参考方案1】:

发生了一些中止/意外的事情

使用某物。像std::lock_guard 这样可以防止由于异常或忘记/意外但必要的unlock() 操作而“挂起”锁。

原理非常简单,您可以轻松地为任何使用一对以“锁定/解锁”方式对应在一起的方法的机制实现它:

class LockObject // E.g. mutex or alike

public:
    // ...
    void lock();
    void unlock();
;

将保护类构造函数绑定到对锁对象实例的引用,并在构造函数中调用lock(),在析构函数中调用unlock()

template<typename T>
class LockGuard

public:
    LockGuard(T& lockObject)
    : lockObject_(lockObject) 
    
        lockObject_.lock();
    
    ~LockGuard()
    
        lockObject_.unlock();
    

private:
    T& lockObject_;
;

像这样使用LockGuard

// Some scope providing 'LockObject lockObject'
 LockGuard<LockObject> lock(lockObject)
    // Do s.th. when lockObject is locked
 // Call of lockObject.unlock() is guaranteed at least here, no matter what
  // (exception, goto, break, etc.) caused leaving the block's scope.

【讨论】:

但是如果线程被杀死会调用析构函数 @RyanHaining If s.th.就像thread::kill() 操作可用(特定于操作系统?)我希望它能够正确展开堆栈! @RyanHaining 从外部杀死线程在 C/C++ 中是一个相当糟糕的主意。 C++11 的线程 API 一开始就不允许这样做是有原因的。终止线程的正确方法是实现一种机制来发出终止请求信号,然后允许线程自行关闭。 @ComicSansMS 我知道杀死线程是一件可怕的事情,尽管如此,我认为问题是如果一个线程在持有互斥锁时被杀死,有没有办法去解锁它?。这仍然是一个可靠的答案【参考方案2】:

通常线程不应意外终止。您可以尝试使用 try/catch 块。如果您仍然想在线程意外终止时释放资源,您可以创建一个等待第一个线程终止的监控线程。

在 Windows 上,您可以使用 ::WaitForSingleObject(m_htThread, INFINITE)。

一旦第一个线程被终止,您就可以继续释放废弃的锁。 也许您需要添加一些标志来指示终止是否正常。 您可能还必须记住哪个线程正在锁定哪个对象。

如前所述,我不建议使用这种方法,但在极端情况下。

【讨论】:

【参考方案3】:

任何语言或平台解决死锁的方法都是一样的。

始终以相同的顺序获取锁。

编辑:但是您错误地描述了您的问题。这不是僵局。死锁是一个循环的锁链。这只是一个未释放的锁,即锁泄漏。解决方案与任何其他资源泄漏相同:不要。在 C++ 中,这意味着在析构函数中释放资源,并确保调用析构函数。不知何故,您的线程在没有这样做的情况下终止了。找到那个问题并修复它。

【讨论】:

但是他的问题是有一个锁没有被释放,而不是他以错误的顺序获得了第二个锁。所以在这种情况下这不是正确的解决方案。 致谁反对这个:这完全正确,但可能与 OP 描述的情况不符(我认为这是更简单的原因)。 @g-makulik 显然这是一个正确的陈述,但它与 OPs 问题无关。任何未解决该问题的答案都会遭到反对。在这种情况下只有一个锁。 @RyanHaining '但这与 OP 的问题无关' 是的!你是对的!但无论如何,我认为它不值得被否决。这是正确处理死锁(至少在问题标题中提到)的一个重要方面,并且可能会启发 OP 走上他的道路;o) ... @WanderingLogic 在这种情况下,问题根本不是死锁。

以上是关于如何解决 C++ 中的未释放锁问题的主要内容,如果未能解决你的问题,请参考以下文章

如何防止此无锁堆栈函数中的未定义行为和 ABA 问题?

如何解决反应身份验证中的未捕获(承诺中)TypeError?

一个多线程死锁案例,如何避免及解决死锁问题?

在 iPhone 上使用自动释放时如何解决问题?

如何解决 NSScanner 上的“架构 x86_64 的未定义符号”? react-native 中的 Swift pod

如何从 C++ 中的类文件运行函数?