std::thread.join() 死锁

Posted

技术标签:

【中文标题】std::thread.join() 死锁【英文标题】:std::thread.join() deadlock 【发布时间】:2013-06-19 13:01:54 【问题描述】:

不明白这个简单的sn-p为什么会有死锁:

#include <atomic>
#include <thread>
#include <memory>

using namespace std;
class Test 
public:

    Test() : mExit( false )
    
        mThread = thread( bind( &Test::func, this ) );
    

    ~Test()
    
        if ( mThread.joinable() )
        
            mExit = true;
            mThread.join();
        
    

private:
    void func() 
    
        while ( !mExit )
        
            // do something
        
    

private:
    atomic< bool > mExit;
    thread mThread;
;

typedef unique_ptr< Test > TestPtr;
TestPtr gTest;

int main()

    gTest = TestPtr( new Test );
    return 0;

编辑 我输入了错误的contstructor set mExit = true

编辑 2 我正在使用带有 v110_xp 工具集的 msvc2012。

编辑 3 如果我在 main 中明确调用 gTest.release(),问题就会消失

【问题讨论】:

我记得前几天在这里看到了一个与全局对象和线程生命周期有关的类似问题。当然,现在找不到了。只是全局对象销毁和线程不能很好地协同工作,您应该确保在main() 退出时加入所有线程。 @Chad 也许你指的是this question? @Chad: ***.com/questions/17093164/… @pramateek - 是的!这个也是***.com/questions/10915233/… @elvis.dukaj 是bug in VS 【参考方案1】:

我刚遇到这个问题,所以我将真正的答案发布给其他人。

至少在visual studio中,有一个“退出锁”,当线程进入退出代码时被锁定(即在主线程main()之后,f()之后std::thread(f))。

由于您的 Test 类仅在 main() 完成后被破坏,因此“退出锁”被锁定。只有这样你才能设置mExit = true; 并且允许另一个线程完成。然后这个其他线程等待获取已经被主线程占用的“退出锁”,而主线程在mThread.join();中等待导致死锁。

所以是的,您需要在主线程完成之前加入所有线程。

【讨论】:

那么,这种情况的解决方案是什么?如何避免这种“退出锁”的死锁? main() 返回后不要加入线程。特别是,如果一个类在其析构函数中加入一个线程,则永远不要将此类的实例作为全局变量。【参考方案2】:

对我来说,代码看起来还不错,如果它可以与本地 dut 和 global 我怀疑与 deinit 序列相关的类。连接发生在出口的深处,实施可能已经消除了一些结构。不应该是这样,但有可能。

在任何情况下,我总是避免在 main 之前启动线程,并留下任何到达 main 的结尾。我认为那只是自找麻烦。如果您可以重新安排它以强制在更小的点加入,那么整个问题可能会消失。

你也应该使用 atomic_flag 而不是 atomic。

【讨论】:

使用 atomic_flag 比 atomic 或 atomic_bool 有什么好处吗?我必须研究更好的原子。 atomic_flag 肯定是真正的原子的东西,最基本的元素。允许使用内部互斥体实现其他类型。 IMO 不太可能,但为什么要冒险。 @BalogPal 因为atomic_flag 使用起来很痛苦? ;) @ComicSansMS:嗯,这确实是一个有效的动机。 (对于这种简单的情况,差异应该不大。)【参考方案3】:

更改代码

gTest = TestPtr(新测试);

自动 gTest = std::make_unique();

消除问题。

上述问题与全局对象有关。

【讨论】:

以上是关于std::thread.join() 死锁的主要内容,如果未能解决你的问题,请参考以下文章

std::thread::join 无限期地阻塞在 main 之外

OpenCV 分配导致 std::thread::join 中的段错误

在多线程应用程序中使用 mongodb 的正确方法

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thre

java.lang.RuntimeException: Handler (android.os.Handler) sending message to a Handler on a dead thre

计算机操作系统 死锁 -- 产生死锁的必要条件死锁的处理方法(鸵鸟策略死锁检测与死锁恢复死锁预防死锁避免)