シングルトンモードの概要
シングルトンモードでは、グローバルでは、シンプルインタレストモードのクラスインスタンスは1つしか存在できず、この一意のインスタンスにアクセスするためのグローバルアクセスポイントが提供されます。
単利モデルの特徴は次のとおりです。
- このクラスのインスタンスは1つだけです。
- このインスタンスは自分で作成する必要があります
- このインスタンスをシステム全体に自分で提供する必要があります
シングルトンモード構造
シングルトンパターンの構造は非常に単純で、シングルトンクラスという1つのクラスしか含まれていません。複数のオブジェクトが作成されないようにするには、そのコンストラクターをプライベートにする必要があります。
一方、一意のインスタンスにアクセスするためのグローバルアクセスポイントを提供するために、シングルトンクラスはインスタンスを返すためのパブリックメソッドgetInstanceを提供します。
シングルスレッド
このクラスのコンストラクターはプライベートであり、静的メンバー変数m_instanceとメンバー関数GetInstance()が含まれています。GetInstance()を使用して、このクラスのポインターを返します。
最後の例:
#include<iostream>
#include<thread>
#include<mutex>
#include<algorithm>
using namespace std;
class MyCAS
{
public:
static MyCAS *GetInstance()
{
if (m_instance == NULL)
{
m_instance = new MyCAS();
cout << "MyCAS Set" << endl;
}
return m_instance;
}
private:
MyCAS() {
}
static MyCAS *m_instance;
};
MyCAS *MyCAS::m_instance = NULL;
int main()
{
MyCAS *ptr1 = MyCAS::GetInstance();
MyCAS *ptr2 = MyCAS::GetInstance();
return 0;
}
コンストラクターはプライベートであるため、シングルトンモードはクラス内でのみインスタンス化できることがわかります。同時に、インスタンスオブジェクトインスタンスはグローバル静的静的であるため、インスタンスは1回しか作成できないことが保証されています。
マルチスレッド
次のマルチスレッドの状況を考えてみましょう。m_instanceは空です。2つのスレッドが関数GetInstance()を同時に実行すると、m_instance = new MyCAS()が複数回実行され、複数のオブジェクトがプログラムに表示されます。シングルトンパターンの本来の意図に明らかに反しています。
#include <iostream>
#include <thread>
#include <mutex>
#include <algorithm>
using namespace std;
mutex resource_mutex;
class MyCAS
{
public:
static MyCAS *GetInstance()
{
// double check
if (m_instance == NULL)
{
unique_lock<mutex> guard(resource_mutex);
if (m_instance == NULL)
{
m_instance = new MyCAS();
cout << " MyCAS Set ! " << endl;
}
}
return m_instance;
}
private:
MyCAS() {
}
static MyCAS *m_instance;
};
MyCAS *MyCAS::m_instance = NULL;
void MyFunc()
{
cout << " Thread Start " << endl;
MyCAS *ptr = MyCAS::GetInstance();
cout << " Thread Stop " << endl;
}
int main()
{
thread obj1(MyFunc);
thread obj2(MyFunc);
obj1.join();
obj2.join();
return 0;
}
call_once()
フラグビットflag_onceはcall_once()で設定されます。このフラグビットを記録することにより、関数が呼び出されたかどうかが判別され、関数が1回だけ呼び出されることが保証されます。別のスレッドが関数call_once()を再度呼び出すと、関数は実行されなくなります。
#include <iostream>
#include <thread>
#include <mutex>
#include <algorithm>
using namespace std;
once_flag g_flag;
class MyCAS
{
public:
static void CreatInstance()
{
m_instance = new MyCAS();
cout << " MyCAS Set " << endl;
}
static MyCAS *GetInstance()
{
call_once(g_flag, CreatInstance);
return m_instance;
}
private:
MyCAS() {
}
static MyCAS *m_instance;
};
MyCAS *MyCAS::m_instance = NULL;
void MyFunc()
{
cout << " Thread Start " << endl;
MyCAS *ptr = MyCAS::GetInstance();
cout << " Thread Stop " << endl;
}
int main()
{
thread obj1(MyFunc);
thread obj2(MyFunc);
obj1.join();
obj2.join();
return 0;
}