258

言い換えれば、このシングルトン実装はスレッドセーフですか?

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    static Singleton()
    {
        instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return instance; }
    }
}
4

10 に答える 10

199

静的コンストラクターは、クラスのインスタンスが作成される前、または静的メンバーがアクセスされる前に、アプリケーション ドメインごとに 1 回だけ実行されることが保証されています。https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

示されている実装は、最初の構築ではスレッド セーフです。つまり、Singleton オブジェクトを構築するためにロックや null テストは必要ありません。ただし、これは、インスタンスの使用が同期されることを意味するものではありません。これを行うにはさまざまな方法があります。以下に1つ示しました。

public class Singleton
{
    private static Singleton instance;
    // Added a static mutex for synchronising use of instance.
    private static System.Threading.Mutex mutex;
    private Singleton() { }
    static Singleton()
    {
        instance = new Singleton();
        mutex = new System.Threading.Mutex();
    }

    public static Singleton Acquire()
    {
        mutex.WaitOne();
        return instance;
    }

    // Each call to Acquire() requires a call to Release()
    public static void Release()
    {
        mutex.ReleaseMutex();
    }
}
于 2008-08-10T08:46:48.413 に答える
91

これらの回答はすべて同じ一般的な回答を示していますが、注意点が 1 つあります。

ジェネリック クラスのすべての潜在的な派生は、個々の型としてコンパイルされることに注意してください。したがって、ジェネリック型の静的コンストラクターを実装するときは注意してください。

class MyObject<T>
{
    static MyObject() 
    {
       //this code will get executed for each T.
    }
}

編集:

デモンストレーションは次のとおりです。

static void Main(string[] args)
{
    var obj = new Foo<object>();
    var obj2 = new Foo<string>();
}

public class Foo<T>
{
    static Foo()
    {
         System.Diagnostics.Debug.WriteLine(String.Format("Hit {0}", typeof(T).ToString()));        
    }
}

コンソールで:

Hit System.Object
Hit System.String
于 2008-12-02T22:46:03.103 に答える
30

静的コンストラクターの使用は、実際にスレッドセーフです。静的コンストラクターは、1 回だけ実行されることが保証されています。

C# 言語仕様から:

クラスの静的コンストラクターは、特定のアプリケーション ドメインで最大 1 回実行されます。静的コンストラクターの実行は、アプリケーション ドメイン内で次のイベントの最初の発生によってトリガーされます。

  • クラスのインスタンスが作成されます。
  • クラスの静的メンバーのいずれかが参照されています。

そうです、シングルトンが正しくインスタンス化されることを信頼できます。

Zooba は、静的コンストラクターがシングルトンへのスレッドセーフな共有アクセスを保証しないという優れた点を (私も 15 秒前に!) 述べました。それは別の方法で処理する必要があります。

于 2008-08-10T08:46:52.577 に答える
9

c# シングルトンに関する上記の MSDN ページの Cliffnotes バージョンは次のとおりです。

次のパターンを常に使用してください。間違いはありません。

public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();

   private Singleton(){}

   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}

明らかなシングルトン機能を超えて、次の2つのことが無料で提供されます(c ++のシングルトンに関して):

  1. 遅延構築 (または呼び出されなかった場合は構築なし)
  2. 同期
于 2011-11-23T19:34:05.087 に答える
6

静的コンストラクターは、アプリ ドメインごとに 1 回だけ起動することが保証されているため、アプローチは問題ありません。ただし、機能的には、より簡潔なインライン バージョンと違いはありません。

private static readonly Singleton instance = new Singleton();

物事を遅延して初期化する場合、スレッドの安全性はより問題になります。

于 2008-08-10T08:48:33.697 に答える
3

Common Language Infrastructure 仕様では、「型初期化子は、ユーザー コードによって明示的に呼び出されない限り、任意の型に対して 1 回だけ実行される」ことが保証されています。(セクション 9.5.3.1.) したがって、Singleton::.cctor を直接呼び出して (可能性は低い) 風変わりな IL を持っていない限り、Singleton 型が使用される前に静的コンストラクターが 1 回だけ実行され、Singleton のインスタンスが 1 つだけ作成されます。 Instance プロパティはスレッドセーフです。

Singleton のコンストラクターが Instance プロパティにアクセスする場合 (間接的であっても)、Instance プロパティは null になることに注意してください。プロパティアクセサーでインスタンスがnullでないことを確認することにより、これがいつ発生したかを検出して例外をスローすることが最善です。静的コンストラクターが完了すると、Instance プロパティは null 以外になります。

Zoombaの回答が指摘しているように、Singleton を複数のスレッドから安全にアクセスできるようにするか、Singleton インスタンスの使用にロック メカニズムを実装する必要があります。

于 2008-08-10T08:45:57.977 に答える
2

衒学的なことですが、静的コンストラクターのようなものはなく、むしろ静的型初期化子があります。これは、この点を示す循環静的コンストラクター依存関係の小さなデモです。

于 2010-03-02T12:37:43.320 に答える
1

静的コンストラクターはスレッドセーフであることが保証されています。また、DeveloperZenでシングルトンに関するディスカッションをチェックしてください:http: //web.archive.org/web/20160404231134/http ://www.developerzen.com/2007/07/15/whats-wrong-with-this-code -1-ディスカッション/

于 2008-08-10T23:38:26.520 に答える