WinNTsp6, VC++5sp3という環境です。
とあるsingleton classをこんな感じで作ったのですが、2ヶ所でGetInstance()してみた
ところ、それぞれのポインタには異なる値が入っている「ことがある」、という現象が起
きて困っています。
class CTib
{
public:
static CSystemMonitor* GetInstance();
private:
static CTib *m_pcTib;
}
CTib* CTib::GetInstance()
{
if( m_pcTib==NULL )
{
m_pcTib = new CTib;
}
return m_pcTib;
}
調べてみたところ、どうやらGetInstance()を呼ぶ2ヶ所というのがそれぞれ別のスレッド
から「ほぼ同時」に呼んでいて、先着分のnew処理が終わらぬうちに後着分のif文に到達
してしまうために後着分でもnewが呼ばれてしまうようなのです。
どちらのスレッドが先に呼ぶという保証はないので、呼び側でsleepさせて時間差を作る
という手法は適切ではないと考えています。CTibを確実にsingletonとして機能させる方
法はないでしょうか。
以上、よろしくお願いいたします。
あわわ....置換漏れ。
class CTib
{
public:
static CTib* GetInstance();
private:
static CTib *m_pcTib;
}
が正しいです。
クリティカルセクションを使うといいです。
>クリティカルセクションを使うといいです。
アドバイスありがとうございます。こんな風にしてみました。
------------------------ tib.h
class CTib
{
public:
static CTib* GetInstance();
private:
static CTib *m_pcTib;
}
------------------------ tib.cpp
static CRITICAL_SECTION cs;
CTib* CTib::GetInstance()
{
EnterCriticalSection( &cs );
if( m_pcTib==NULL )
{
m_pcTib = new CTib;
}
LeaveCriticalSection( &cs );
return m_pcTib;
}
で、この場合、InitializeCriticalSection()はどこで呼べばいいのでしょうか。
GetInstance()の先頭でflagを用意して初期化済みかどうかを見るのでは結局冒頭に挙げ
たのと同じ問題が起きると思うのですが。
>で、この場合、InitializeCriticalSection()はどこで呼べばいいのでしょうか。
・グローバルスコープ
・main() の中、スレッドが起動される前
とか。
CCriticalSectionではだめ?
あと、直接関係ないけど、この例はダブルチェッキングロックパターンにすると
パフォーマンスがちょっとあがって幸せかも。
テストに手間取っていましたが、CriticalSectionで使用に耐えうる物が実現できまし
た。アドバイスありがとうございました。