2011-07-29 20 views
1

私はそれの静的インスタンスを作成してシングルトンとして使いたいクラスを持っています。もちろん、私はスレッドセーフであることも望みます。プライベート静的メソッドを使用してシングルトンスレッドを安全にしますか?

私は私的なデータを共有していないと仮定します。しかし、私が間違っていないと、静的オブジェクトインスタンスのメソッドを呼び出すときに、メソッド内の変数がスレッド間で共有され、予測できない結果になるという問題が残っています。

しかし、実際の静的メソッドを呼び出すときには、新しいスタックフレームが作成されるため、スレッドセーフ(それ自体)になります。もう一度、もし私が間違っていないならば。

シングルトンのこのパターンはスレッドセーフであるでしょうか?私は、インターフェイスに基づいてシングルトンを持っている必要があり、異なる実装を持って、戦略の一環として - 私は最初の場所で静的クラスを作成していない理由を不思議に思っている場合には

class Singleton 
{ 
    public object SomeMethod(object arg) { 
     return Singleton.SomeMethodImpl(arg); 

    } 
    private static object SomeMethodImpl(object arg) { 
     // is in unique stack frame? 
     object Result; 
     ... 
     return Result; 
    } 
} 

パターン。これは静的クラスでは機能しません。

+0

シングルトンを作成する方法の良い例が必要な場合は、http://www.dofactory.com/Patterns/PatternSingleton.aspxを参照してください。 –

+0

ちょうどそれをスキミングしました。良い情報 - ブックマーク。私の目的では、クラス内の共有データにアクセスしていないので、ロックを心配する必要はないと思います。 –

答えて

5

メソッドがインスタンスメソッドまたはグローバルスコープ変数から状態を取得していない限り、メソッドはリエントラントでスレッドセーフです。必ずしも静的である必要はありません。そうですね、

int AddTwo(int a, int b) 
{ 
    return a + b; 
} 

これは完全にスレッドセーフで、好きなだけ呼び出すことができます。メソッド間で変数を定義することは、メソッド間で共有されるインスタンス変数であれば問題ありません。

方法など:

string ReverseString(string s) 
{ 
    char[] charArray = s.ToCharArray(); 
    Array.Reverse(charArray); 
    return new string(charArray); 
} 

上記方法にも再入可能およびスレッドセーフです。

静的であるか、異なるスコープからのインスタンスであるかに関わらず、変数の追加を開始するとすぐに、スレッドの安全性に問題が発生します。

class BadExample 
{ 
    private int counter; 

    private void IncrementCounter() 
    { 
     ++counter; 
    } 
} 

上記の例では、IncrementCounter()メソッドはスレッドセーフではありません。

+0

しかし、非ステイティックメソッドでローカル変数を定義すると、スレッドセーフではなくなります。これは私が解決しようとしている問題です。私はプライベートな一時的なストレージが必要なキャッシュから物を引っ張るようなことをしなければなりません。 –

+0

ローカル変数ではない問題です。内容がどこから来るのか。上の例では、すべての "状態"はメソッドの引数から来ています。あなたのケースでは、キャッシュがスレッドセーフであるかどうかによって異なります。どのように書かれていますか?どのように読むのですか? –

+0

キャッシュは正常です、それは 'ConcurrentDictionary'か' HttpContext.Cache'です。しかし、私は、静的インスタンス化されたクラスの非静的メソッドでローカル変数を定義すると、同時に2つのスレッドがメソッドを呼び出してそのローカル変数の同じインスタンスを共有することが困難になるという印象を受けました。 –

0

あなたが何を意味するのか分かっていれば、あなたは正しいです。

object Result; // this is on its unique stack frame and is safe so far 
Result = new ... // creating something on the heap that Result points to 
       // still safe because it's the only reference to it 

複数のスレッドがこれを呼び出しても、ヒープに異なる新しい変数を作成し、異なるスタック上のResultに割り当てます。

唯一の危険は、プライベートフィールドがある場合です。

メソッド内の変数は一時的なものであり、そのメソッドにのみ表示されますと呼びます。後のメソッド呼び出しまたは並行したメソッド呼び出しは、これらの変数を別々に再作成します。

懸念事項は静的フィールドまたはインスタンスフィールドのみです。それらは同期する必要があります。

0

上記のコードは、スレッドセーフであり、指定した理由からです。私が見る問題は、シングルトンを実装していないことです。

スレッドセーフについての主な心配はありますか?その場合、スレッドの安全性は通常、スレッド間で共有されるオブジェクトインスタンスに適用されます。これは、スレッド間で通常のオブジェクトを共有したり、クラスレベルでスタティックデータを作成したりしない限り、大丈夫であるはずです。

私はシングルトンをインターフェイスで使用する例を追加していますが、工場の有無にかかわらず使用しています。注:私はこのコードを実行しませんでした。

public interface ISomething 
{ 
    void Method(); 
} 

public class Class1 : ISomething 
{ 
    public void Method() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class Class2 : ISomething 
{ 
    public void Method() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class Singleton 
{ 
    private static ISomething privateObject; 

    public static ISomething Instance() 
    { 
     lock (privateObject) 
     { 
      if (privateObject == null) 
      { 

       privateObject = new Class1(); 
      } 
     } 

     return privateObject; 
    } 
} 

public class SingletonUsingFactory 
{ 
    private static ISomething privateObject; 

    public static ISomething Instance(int param) 
    { 
     lock (privateObject) 
     { 
      if (privateObject == null) 
      { 
       privateObject = FactoryClass.CreationObject(param); 
      } 
     } 

     return privateObject; 
    } 
} 

public static class FactoryClass 
{ 
    public static ISomething CreationObject(int whatToCreate) 
    { 
     ISomething createdObject; 

     switch (whatToCreate) 
     { 
      case 0: 
       createdObject = new Class1(); 
       break; 
      case 1: 
       createdObject = new Class2(); 
       break; 
      default: 
       throw new Exception(); 
     } 

     return createdObject; 
    } 
} 
+0

アイデアは、これを別の静的クラス、例えば、 'public static Singleton MySingleton = new Singletion()' –

+0

シングルトンパターンを使うと、あなたのインターフェースを実装から独立させることができます。単一のオブジェクトを作成するときにロックを使用するだけです –

関連する問題