読者です 読者をやめる 読者になる 読者になる

Singletonパターンとマルチスレッド

マルチスレッドを考慮してSingletonを実装するとき、アクセスする度にTCriticalSectionを使ってオブジェクトの中身を保護してやらないといけないのかな・・・。

class CSingleton
{
private:
  CSingleton(){}
  CSingleton(const CSingleton& obj) {}
  virtual ~CSingleton(){}

public:
  static CSingleton& getInstance();
  static void release();

private:
  static CSingleton* s_pInstance;
};

CSingleton& CSingleton::getInstance()
{
  if (s_pInstance == NULL) {
    // シングルトンオブジェクトの初期化

    // TCriticalSectionは排他制御を行うVCLクラス
    // unique_ptrってスレッドセーフだっけ?
    std::unique_ptr<TCriticalSection> pCriticalSection(new TCriticalSection);

    // リソースの排他制御開始
    pCriticalSection->Enter();

    // TCriticalSectionの生成時に別スレッドが初期化しているかもしれないので、もう一度チェック。
    // 所謂"double-checked locking"。
    if (s_pInstance == NULL) {
      s_pInstance = new CSingleton();
    }

    // 排他制御終了
    pCriticalSection->Release();
  }
  return *s_pOptions;
}

// newしたので終了時に解放してやる。
void TCriticalSection::release()
{
  if (s_pInstance != NULL) {
    
    // 解放時も排他制御が必要
    std::unique_ptr<TCriticalSection> pCriticalSection(new TCriticalSection);
    pCriticalSection->Enter();
    if (s_pInstance != NULL) {
      delete s_pInstance;
      pInstance = NULL;
    }
    pCriticalSection->Release();    
  }
}

今まで、Singletonは「MeyersのSingleton」で実装していたけど、C++Builder 2009からは"警告 W8104 test.cpp 13: マルチスレッド アプリケーションのコンストラクタでローカル静的変数を使うことは危険"と出力されるようになった。

class CSingleton {
private:
  CSingleton() {}
  CSingleton(const CSingleton& obj) {}
public:
  virtual ~CSingleton() {}
public:
  CSingleton& getInstance();
};

CSingleton& CSingleton::getInstance()
{
  static CSingleton instance;  // W8104が発生。
  return instance;
}

これから、資源の保護とかも考えなければいけないと。アクセサでも、資源の保護が必要なのかよく判らん。少なくとも、シングルトンオブジェクトの読み書き時は排他制御しないといけなさそうだ。('A`)マンドクセ

追記:
こことかここによると、double-checked lockingも結構問題を抱えているんだね・・・。('A`)
完璧な「スレッドセーフ」なんて、よほどのことをしないと実現出来そうにないな。(´・ω・`)ショボーン