38575


タイトルの件、WCFサービス上でシングルトンクラスを扱うことを想定してスレッドセーフな  
実装をしたいと考えております。  
検索もしてみたのですが、いくつか方法があるようで実際どれが正しいのか  
よく分かりません。。

大変恐縮ですが、サンプルコード等のリンクでも構いませんので、  
ご教示頂けないでしょうか？


CC BY-SA 3.0
2017-10-10T23:57:09.213
38573
2017-10-11T09:32:39.357
9228
question
c# アルゴリズム
C#でスレッドセーフなシングルトンクラスを実装したい


シングルトンパターンにはおおむね3パターンの実装方法があります。

最初の方法は

[code]

    class Hoge
    {
        private static Fuga _Piyo;
        public static Fuga Piyo => _Piyo ?? (_Piyo = new Fuga());
    }
    
[/code]

とプロパティにアクセスしたタイミングでインスタンスを作成するものです。この方法は`_Piyo`が`null`かどうかを判定してから`new
Fuga()`を代入するまでの間に他のスレッドでも`new Fuga()`を作成し始め、結果的にインスタンスが複数作成される危険性があります。つまり
**スレッドセーフではありません** 。

この問題はスタティックメンバーの初期化子を使用すると回避できます。

[code]

    class Hoge
    {
        public static Fuga Piyo { get; } = new Piyo();
    }
    
[/code]

このような実装は`static`メンバーの初期化がランタイムにより厳密に一度しか行われないことが保証されるため、`new
Fuga()`が複数回呼び出されることはありません。ですが`Hoge`型が **初期化されるタイミングが不定** という問題があります。

タイミングも制御したい場合は、`static`初期化子でロックオブジェクトを作成します。

[code]

    class Hoge
    {
        private static readonly object _Lock = new object();
        private static Fuga _Piyo;
        public static Fuga Piyo
        {
            get
            {
                lock (Lock)
                {
                    if (_Piyo == null)
                    {
                        _Piyo = new Fuga();
                    }
                    return _Piyo;
                }
            }
        }
    }
    
[/code]

どれが正しいというよりかは、最初の2個の欠点を許容できるかどうかで方法を選べばよいと思います。

なお作成されたインスタンスの実装がスレッドセーフであるかは別問題です。これに関しては個別の設計になりますので

  * ローカルな状態をフィールドで共有しない
  * 状態をインスタンス内で共有する場合は適切にロックを行う

といった程度しかアドバイスできません。


CC BY-SA 3.0
2017-10-11T00:45:21.513
38575
2017-10-11T00:53:10.143
2017-10-11T00:53:10.143
5750
5750
38573
answer


インターネット インフォメーション
サービスでのホスティングとなると、[状態管理とプロセスのリサイクル](https://msdn.microsoft.com/ja-
jp/library/aa751802\(v=vs.110\).aspx#Anchor_3)にて次のように説明されています。

> IIS ホスト環境は、メモリにローカル状態を保持しないサービスに最適化されています。IIS は、さまざまな外部および内部イベントに応答してホスト
> プロセスをリサイクルするため、メモリのみに格納される揮発性の状態はすべて失われます。IIS でホストされるサービスは、それぞれの状態をプロセスの外部
> (データベースなど)、またはアプリケーションのリサイクル イベントが発生した場合に簡単に再作成できるメモリ内キャッシュに格納する必要があります。

何らかの手段でシングルトンを実現しても、IISによってプロセスをリサイクルされると全てがリセットされます。更に既定では29時間毎に定期的にリサイクルされる設定になっています。その他、ワーカープロセス数を２以上に設定した場合、複数プロセスにまたがるためにどのような努力をしてもシングルトンは実現できません。

インターネット インフォメーション サービスでのホスティングを行うのであれば、シングルトンに頼らない実装をお勧めします。

* * *

> プロセス間でシングルトンクラスの情報を共有する必要はありません。 1プロセス内でシングルトンクラスの情報を共有できればと考えております。
> 基本的にシングルトンクラスの動作設定は、設定ファイルに記載しており、 インスタンス取得後、初期化処理をしてシングルトンクラスに保持しています。

コメントを読む限り、厳密な意味でのシングルトンを求めているわけではないように見受けられます。キャッシュとして初期化済みインスタンスがあれば再利用し、なければ新規にインスタンスを用意すれば十分かと。[Weak
References](https://msdn.microsoft.com/ja-
jp/library/ms404247\(v=vs.110\).aspx)という概念もありますがインスタンスを破棄する必要性も特にないためあまり関係なさそうです。また[限定的な初期化](https://msdn.microsoft.com/ja-
jp/library/dd997286\(v=vs.110\).aspx)も用意されていますがpgrhoさんが説明されているように特に使用しなくても実現できます。

１点気になるのは「インスタンス取得後、初期化処理をして」と言及されていることです。初期化処理はコンストラクターで行うべきです。インスタンス作成済み＝初期化済みと状態を一致させることができます。


CC BY-SA 3.0
2017-10-11T06:08:25.557
38591
2017-10-11T09:32:39.357
2017-10-11T09:32:39.357
4236
4236
38573
answer