メモ

プログラムを書いているときに詰まった部分などを備忘録的に書いていきます。

Singletonでのthread終了時にjoinで固まる

VisualStudio環境での話です(VS2012で確認)
gcc(4.9.2)環境では正常に動作します。

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

class Hoge
{
public:

    static Hoge& get()
    {
        static Hoge hoge;
        return hoge;
    };

    void run()
    {
        while( false == m_end )
        {
            sleep(100);
        }
    }

    void stop()
    {
        m_end = true;
    }

    static void sleep(unsigned int ms)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(ms));
    }

private:

    Hoge()
        : m_thread()
        , m_end(false)
    {
        m_thread = std::thread( &Hoge::run, this );
    }

    virtual ~Hoge()
    {
        stop();
        if ( m_thread.joinable() )
        {
            m_thread.join();
        }
        std::cout << "thread end" << std::endl;
    }

    Hoge(const Hoge& rhs);
    Hoge& operator=(const Hoge& rhs);

    std::thread         m_thread;
    std::atomic<bool>    m_end;
};

int main()
{
    Hoge::get();
    Hoge::sleep(100);
    return 0;
}

上記のコードを実行すると終了時に固まります。
何が起こっているかというと多分以下の通り
・mainが終了
Hogeのデストラクタで動かしている子供スレッドの終了指示
・joinで子供スレッドが終わるのを待つ
・run関数自体は終わるが_Cnd_do_Broadcast_at_thread_exitでメインスレッドの終了待ちをしている?
・結果joinとメインスレッド終了待ちでデッドロック
いまのところ、とりあえずjoinをdetachに変えてしのいでます。

     if ( m_thread.joinable() )
        {
#if 0
           m_thread.join();
#else
            m_thread.detach();
#endif
        }

ちなみに_Cnd_do_Broadcast_at_thread_exitを通るのを確認するために
ランタイムライブラリのオプションを/MTdにしてます。