C++: 05. シングルトン モード

シングルトンパターン

クラスは 1 回だけインスタンス化して、オブジェクトを生成できます。

クラスでインスタンスを構築するには、コンストラクターを渡す必要があるため、クラスのコンストラクターを外部から呼び出してインスタンスが構築されないようにするには、コンストラクターのアクセス許可を protected または private としてマークする必要があります。

また、グローバル アクセス ポイントに提供する必要がある場合は、静的関数をクラス内で定義して、クラス内で一意に構築されたインスタンスを返す必要があります。

遅延スタイル:クラス インスタンスは、初めて使用されるときにインスタンス化されます. 訪問回数が少ない場合、遅延スタイルは時間をスペースと交換するために使用されます. インスタンス化はアトミック操作ではないため、安全ではありません. インスタンス化プロセス中、ポインターに値を割り当てる前に、CPU はスレッドを切り替え、複数のオブジェクトを生成します。

ハングリー チャイニーズ スタイル:シングルトン クラスが定義されたときにインスタンス化します。訪問数が多く、スレッド数が多い場合は、ハングリー チャイニーズ スタイルを採用し、スペースを時間に交換します。最初にインスタンス化されるため、スレッドセーフです。

懒汉式:
class Single           
{                            
public:
	static pthread_mutex_t mtx;   互斥锁

***************在饿汉式中该函数只需要一个return***************
	static Single* get_Single()
	{
		if (p == NULL)  双重检查
		{
			pthread_mutex_lock(&mtx);
			if (p == NULL)  多线程,需要加锁,保证其他线程无法获取锁而阻塞。
                                        如果不加锁,又因为实例化不是原子操作,导致可能有多个进程创建多个对象
			{
				p = new Single;  如果还没有唯一的对象就先生成,实例化,不是原子操作
			}
			pthread_mutex_unlock(&mtx);
		}
		return p;
	}
private:
	static Single* volatile p;
	Single(){}
};
pthread_mutex_t Single::mtx = PTHREAD_MUTEX_INITIALIZER;  创建互斥锁

***************懒汉与饿汉的区别就在于这个静态成员变量实例化的位置不一样***************
Single* Single::p = NULL;  静态成员变量初始化       懒汉式在此处实例化
 
int main()
{
	Single* tmp = Single::get_Single();  用作用域加成员函数名调用静态函数。
	Single* tmp1 = Single::get_Single(); 
	cout <<tmp <<endl<<tmp1<<endl;
	return 0;
}

いくつかの問題を解決します。

1. 静的関数と静的メンバー変数を使用する理由

クラスで関数を呼び出すには、最初にオブジェクトを構築する必要があります。その後、オブジェクトを使用してクラスのメンバー メソッドを呼び出すことができます。しかし、この方法はシングルトンモードには絶対に適していません。もう 1 つのメソッドは静的関数で、クラス名を使用して直接呼び出すことができます。静的関数は、静的メンバー メソッドのみを呼び出すことができます。

2. なぜ再確認するのですか?

徹底的に分析してみましょう. まず, シングルトンモードの要件を満たすために, つまり, p はオブジェクトを作成しました, そしてそれはもはや作成できません. 判断の層を外側に追加して,シングルトンがシングルスレッドの場合にうまく実装できること。ただし、これは単一のスレッドの下でのみ満たされます. 複数のスレッドがある場合、CPU タイム スライスの回転により、p への割り当て中に切り捨てられ、別のプロセスもオブジェクトを作成する可能性があります. これを回避するには状況では、ミューテックスを外側に追加する必要があります。ただし、ロック操作はカーネルによって行われます。つまり、ロックが保持されているかどうかを確認するたびに、カーネルに陥る必要があります。この場合、シングルスレッドには不向きであり、シングルスレッドがロックとロック解除に時間とリソースを消費する必要がないことがわかりました。そのため、判断の最外層を追加し、p が NULL でない場合は直接スキップし、ロック操作を実行しなくなりました。

3. プライベート静的メンバ変数 volatile とは?

揮発性:

1. 複数のスレッドが共有変数に対してスレッド キャッシュ操作を実行しないようにする. 1 つのスレッドが共有変数を変更すると、他のスレッドはそれを時間内に見ることができません.

説明: CPU レジスタとメモリ上のスペースに加えて、2 つのマルチスレッド共有変数の間にキャッシュ バッファ領域もあり、データのコピーがスレッド スタックにキャッシュされます。命令が与えられると、CPUは秒を取っています。p ポインターがインスタンス化されていないという誤解。

2.コンパイラが値操作を含むコードを並べ替えないようにする

おすすめ

転載: blog.csdn.net/qq_41214278/article/details/83718210