2013-06-19 44 views
8

我不明白为什么这个简单的代码段有一个死锁:的std ::的Thread.join()的僵局

#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设置MEXIT =真

编辑2 我正在使用msvc2012和v110_xp工具集。

编辑3 问题消失,如果我明确地内主要

+3

'mExit = false' ?? –

+0

我输错了,抱歉。问题依然存在。 –

+0

嗯。在你正确使用原子之前,这可能不会变好。并使用调试器来找出线程正在做什么。在杂草中关闭的可能性相当大,阻止了一些操作系统调用,而不是一次又一次地燃烧100%核心检查退出条件。 –

回答

6

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

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

由于您的测试类只在main()完成后被破坏,所以“退出锁定”被锁定。只有您设置了mExit = true;并且允许其他线程完成。然后这个其他线程等待获得主线程已经占用的“退出锁定”,而主线程在mThread.join();中等待,导致死锁。

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

3

调用gTest.release()给我的代码看起来不错,如果它的好与当地DUT坏全球我怀疑类相关deinit序列。连接在退出时发生很深,实现可能已经消除了一些结构。它不应该是这样,但可能。

在任何情况下,我总是避免在main之前启动线程,并留下main的任何延伸结束。我认为只是要求麻烦。如果你可以重新安排它来强制连接,那么整个问题可能会消失。

另外你应该使用原子上的atomic_flag。

+0

使用atomic_flag原子或atomic_bool我有一些好处吗?我必须研究更好的原子。 –

+0

atomic_flag是一个确定的原子事物,最基本的元素。其他类型允许使用内部互斥实现。国际海事组织不太可能,但为什么要冒险 –

+0

@BalogPal因为'atomic_flag'是使用的皇家痛苦吗? ;) – ComicSansMS

0

将代码从

gTest = TestPtr(new Test);

auto gTest = std :: make_unique();

消除了这个问题。

上面的问题与全局对象一样。