std::thread.join()死锁

10

我不明白为什么这个简单的代码片段会出现死锁:

#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;
}

编辑 我打错了构造函数,将mExit设置为true。

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

编辑3 如果我在main函数中显式调用gTest.release(),问题就会消失。


1
我记得就在前几天看到一个关于全局对象和线程生命周期的类似问题。当然,现在我找不到它了。问题是全局对象的销毁和线程不兼容,你应该确保所有线程在 main() 退出时都已经结束。 - Chad
1
@Chad 也许你指的是这个问题 - ComicSansMS
1
@Chad:为什么这个C++静态单例永远不会停止? - Pragmateek
1
@pramateek - 是的!这个也是 https://dev59.com/1Wgv5IYBdhLWcg3wBMEK - Chad
2
@elvis.dukaj 这是Visual Studio中的一个错误 - ComicSansMS
显示剩余9条评论
3个回答

8
我刚刚遇到了这个问题,所以我为其他人发布了真正的答案。
在Visual Studio中至少有一个“退出锁定”,当线程进入退出代码(即主线程的main()之后,f()std::thread(f)之后)时被锁定。
由于Test类只有在main()完成后才被销毁,“退出锁定”被锁定。然后您才设置mExit = true;并允许其他线程完成。此其他线程然后等待获取已被主线程占用的“退出锁定”,而主线程则在mThread.join();中等待,导致死锁。
因此,在主线程完成之前,您需要加入所有线程。

那么,针对这种情况有什么解决方案呢?如何避免这个“退出锁”的死锁问题? - TonySalimi
1
不要在main()函数返回后加入线程。特别是,如果一个类在其析构函数中加入了一个线程,永远不要将此类的实例作为全局变量。 - god

3
对我而言,代码看起来没问题。如果在本地正常但在全局不好的话,我会怀疑与析构顺序相关的类。加入操作深入到退出流程中,并且实现可能已经消除了一些结构。这不应该是事实,但有可能发生。
无论如何,我总是避免在main之前启动线程,并在main结束时保持任何线程的运行。我认为这只会给自己找麻烦。如果您可以重排它,以在稍早的时刻强制加入,整个问题可能会消失。
此外,您可能应该使用atomic_flag而不是atomic。

我使用atomic_flag相比于atomic<bool>或atomic_bool有什么好处吗?我需要更深入地研究原子操作。 - Elvis Dukaj
atomic_flag是一个确保原子性的真正原子元素,是最基本的元素。其他类型可以使用内部互斥锁来实现。在我看来这种情况不太可能发生,但为什么要冒险呢? - Balog Pal
@BalogPal 因为atomic_flag使用起来真是让人头疼,是吧? ;) - ComicSansMS
@ComicSansMS:嗯,那确实是一个有效的动机。(对于这种简单情况,差别不应该太大。) - Balog Pal

0

将代码从

gTest = TestPtr( new Test );

改为

auto gTest = std::make_unique();

可以消除问题。

上述问题涉及全局对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接