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

編集 コンストラクター set mExit = true を間違って入力しました

編集 2 v110_xp ツールセットで msvc2012 を使用しています。

編集 3 main 内で明示的に gTest.release() を呼び出すと、問題は消えます

4

3 に答える 3

8

この問題が発生したばかりなので、他の人に本当の答えを投稿します。

少なくともビジュアルスタジオには、スレッドが終了コードに入ったときにロックされる「終了ロック」があります(つまりmain()、メインスレッドの場合は後、の場合は後f()std::thread(f)

Test クラスは完了後にのみ破棄main()されるため、「終了ロック」がロックされます。そうして初めて、設定mExit = true;し、他のスレッドを完了することができます。次に、この別のスレッドは、メイン スレッドによって既に取得されている「終了ロック」を取得するために待機しますが、メイン スレッドが待機している間mThread.join();にデッドロックが発生します。

はい、メインスレッドが完了する前にすべてのスレッドに参加する必要があります。

于 2015-05-26T13:33:19.910 に答える
3

私にはコードは問題ないように見えますが、ローカルの dut がグローバルで問題がなければ、deinit シーケンスに関連するクラスが疑われます。結合は終了時に深く発生し、実装によっていくつかの構造が既に排除されている可能性があります。そうであってはなりませんが、可能です。

いずれにせよ、私は常にメインの前にスレッドを開始することを避け、メインの最後に到達したままにします。私はそれがトラブルを求めているだけだと考えています。少し前の時点で結合を強制するように再配置できれば、問題全体が蒸発する可能性があります。

また、おそらくatomicよりもatomic_flagを使用する必要があります。

于 2013-06-19T13:39:11.207 に答える