C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 126 を表示中)
■74859 / )  Re[6]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (43回)-(2015/02/03(Tue) 12:10:58)
2015/02/05(Thu) 15:54:36 編集(投稿者)
2015/02/03(Tue) 12:12:52 編集(投稿者)

まとめです。

ヘッダファイルのみでスレッドセーフなシングルトンクラスを実現する方法

■局所的な静的変数(関数内のstatic変数)とCAS(Compare And Swap)を使う方法
ヘッダファイルのみでは『静的クラスメンバー変数の実体定義』は困難なので関数内のstatic変数を使います。
関数内のstatic変数は最初に関数が呼び出された時点で初期化されますが、再入呼び出しされた場合の動作は
未定義となっています。
そのためスレッドセーフではないので、CASを使ってスレッドセーフを実現します。
#今回はCAS等のアトミックな操作にはWindows APIを利用しています。
#同様なAPIは他のOSにもあると思いますので、他のOSでも実現可能だと思います。

その1
No74661 で最初に提示した方法です。
関数内のstatic変数としてポインターを持ち、初回呼び出し時に動的に実体を生成します。
スレッドセーフとなるようにCASで振り分けます。

欠点
newで動的に実体を生成していますが、この実体はdeleteされません。
そのため、デストラクターは呼ばれませんし、メモリーリークと検出されてしまいます。
ただし、プロセス終了時にOSが解放しますのでデストラクターでの処理がないのであれば問題はありません。
また、コンストラクターは複数回呼ばれる可能性があるので、『1つしかない資源を占有』するような処理を
コンストラクターに記述することは出来ません。

その2
No74684 で提示した方法です。
よく使われる関数内のstatic変数として実体を持つ方法です。
(提示したコード内の GetInstanceImpl関数)
このままではスレッドセーフではないので、GetInstanceImplはprivateとして、
安全に呼び出すためのラッパー GetInstance() を公開しています。
GetInstance() の役割は CASを利用することで 初期化シーケンス中は GetInstanceImpl() を絶対に1回しか呼ばないようにすることです。

プロセス終了前にデストラクターも呼ばれますし、特に欠点はないと思いますが多少実装が複雑です。

2/5 追記
このコードはVisual C++ 2005以降でビルドし、Windows上で実行した場合のみ安全です。
それ以外では、メモリバリアに関する考慮が必要になる場合があります。
後続の投稿を参照してください。

■ヘッダファイルのみで『静的クラスメンバー変数の実体定義』を実現する方法

静的クラスメンバー変数(クラススコープの静的変数)は早い段階で初期化されるのでスレッド競合が発生しません。
よって、静的クラスメンバー変数を使えばスレッドセーフが実現できることになります。
ですが通常の方法ではヘッダファイルでは『静的クラスメンバー変数の実体定義』は出来ないです。
それを実現する方法です。

その1
No74856 でAtata!!さんがご提示してくださった方法です。
Visual C++固有の機能となりますが、__declspec(selectany) を使えばヘッダファイルのみで
『静的クラスメンバー変数の実体定義』が可能です。

その2
クラステンプレートを利用すれば、__declspec(selectany)と同様にヘッダファイルのみで
『静的クラスメンバー変数の実体定義』が可能と思われます。
(具現化される型ごとに静的クラスメンバーの実体が定義されるはず)
が、今回は試していません。

注意点
静的クラスメンバー変数を用いた場合、スレッド競合は解決できますが、『異なる翻訳単位間の初期化順問題』
が発生します。
今回のケースでは『異なる翻訳単位間の初期化順問題』は発生しないですが、それが発生するようなケースに
この方法を用いる場合はさらに工夫が必要となります。

■その他
C++ 11 であれば No74704 でεπιστημη さんが示してくださった方法が使えますし、
(準拠していれば)局所的な静的変数の初期化が絶対に一度しか行われないことが保証されて
いたりするのでもっと簡単に実現できると思われます。

ヘッダファイルのみという条件を外せば、 No74665 でAzuleanさんが教えてくださったサイトが
参考になります。

私の解釈が間違っている点などがありましたらご指摘ください。
問題が無いようなら解決にチェックをつけたいと思います。

2/3 12:13 すみません、誤字修正しました。
返信 編集キー/


管理者用

- Child Tree -