17

C++ でシングルトン (静的バージョン) を実装しました。私はこのパターンと潜在的なスレッド セーフの問題に関するすべての論争を知っていますが、なぜこの正確な実装が停止しないのか興味があります。プログラムは決して終了せず、最後にデッドロック状態のままです。

singleton.h:

#pragma once
#include <thread>
#include <atomic>

class Singleton
{
public:
    static Singleton& getInstance();

private:
    std::thread mThread;
    std::atomic_bool mRun;

    Singleton();
    ~Singleton();
    void threadFoo();
};

シングルトン.cpp

#include "singleton.h"

Singleton& Singleton::getInstance()
{
    static Singleton instance;
    return instance;
} 

Singleton::Singleton()
{
    mRun.store(true);
    mThread = std::thread(&Singleton::threadFoo, this);
}

Singleton::~Singleton()
{
    mRun.store(false);

    if(mThread.joinable())
        mThread.join();
}

void Singleton::threadFoo()
{
    while(mRun)
    {
    }
}

main.cpp

#include "singleton.h"

int main()
{
    Singleton::getInstance();
    return 0;
}

私がすでに知っていること:

  • スレッドは終了します
  • メインスレッドが結合でスタックしている
  • コンストラクターを公開し、main() で Singleton のインスタンスを作成すると、正しく終了します。

Visual Studio 2012 を使用しています。アドバイスありがとうございます。

4

6 に答える 6

22

メイン スレッドでは、main()終了後に CRT が終了ロックを取得し、バックグラウンド スレッドが終了するのを待機する静的インスタンス デストラクタを呼び出します。

バックグラウンド スレッドでは、スレッド関数が終了した後、CRT は終了ロックを取得してスレッド終了作業を実行しようとします。このスレッドが終了するのを待っているメインスレッドによって終了ロックが保持されているため、これは永久にブロックされます。

これは、CRT の実装によって引き起こされる単純なデッドロックです。肝心なのは、Windows の静的インスタンス デストラクタでスレッドの終了を待つことができないということです。

于 2013-06-13T18:48:04.897 に答える
7

void __cdecl _lock(int locknum)中までたどり着きましたmlock.c。終了するmain()と、メイン スレッドはそこに移動し、 critical section に入りますEnterCriticalSection( _locktable[locknum].lock );。次に、Singleton デストラクタが呼び出され、他のスレッドが同じクリティカル セクションに入ろうとしますが、できないため、メイン スレッドがクリティカル セクションを離れるのを待機し始めます。次に、メインスレッドは他のスレッドを待ちます。だからバグだと思います。

于 2013-06-13T18:47:09.627 に答える
4

標準の [basic.start.term] を参照してください。

シグナルハンドラ (18.10) 内で許可されていない標準ライブラリオブジェクトまたは関数の使用があり、それが静的ストレージ期間を持つオブジェクトの破棄の完了 (1.10) および std::atexit 登録済み関数の実行 (18.5) の前に発生しない場合、プログラムには未定義の動作があります。[注: オブジェクトの破棄前に発生しない静的ストレージ期間を持つオブジェクトの使用がある場合、プログラムは未定義の動作をします。これらの要件を満たすには、std::exit の呼び出しまたは main からの終了の前にすべてのスレッドを終了することで十分ですが、必須ではありません。これらの要件により、スレッド マネージャは static-storage-duration オブジェクトとして許可されます。—終わりのメモ]

于 2013-06-13T20:51:11.227 に答える