1

質問、スレッドAとスレッドBがあり、これらの両方がシングルトンオブジェクトとそのプロパティにアクセスする必要があるとしましょう。

現在、シングルトンは次のようになっています。

public class Singleton{

        #region fields
        private static Singleton singletonObject;
        private double value1= 0;
        private double value2= 0;
        private double value3= 0;
        private double value4= 0;
        private object locker = null;
        #endregion

        // private constructor. This will avoid creating object using new keyword
        private Singleton() {
            locker = new object();
        }

        // public method which will be called
        public void GetName() {
            Console.WriteLine("singleton Object");
        }
        public static Singleton Instance() {
            // this object will be used with lock, so that it will be always one thread which will be executing the code
            object instanceLocker = new object();
            // put a lock on myObject. We won't be able to use singleTonObject becuase it will be null. lock is to make the object thread safe.
            // lock can't be worked with null objects.
            lock (instanceLocker) {
                // check whether the instance was there. If it's not there, then create an instance.
                if (singletonObject == null) {
                    singletonObject = new Singleton();

                }
            }
            return singletonObject;
        }

        public double Value1 { get { lock (locker) { return value1; } } set { lock (locker) { value1= value; } } }
        public double Value2 { get { lock (locker) { return value2; } } set { lock (locker) { value2= value; } } }
        public double Value3 { get { lock (locker) { return value3; } } set { lock (locker) { value3= value; } } }
        public double Value4 { get { lock (locker) { return value4; } } set { lock (locker) { value4= value; } } }


    }

私の質問。スレッドセーフなプロパティを持つよりも、より良いアプローチはありますか?

ありがとう、

4

3 に答える 3

4

現在、コードは完全に壊れています。すべての呼び出し中にロックする新しいオブジェクトを作成しています。他のスレッドはそれについて知ることはないので、それは完全に無意味です。

巧妙な方法でそれを修正しようとわざわざしないでください。静的変数初期化子で初期化するだけです。

private static Singleton singletonObject = new Singleton();

素晴らしくてシンプル。

C#でのシングルトンパターンの実装(Lazy<T>.NET 4での使用を含む)の詳細については、トピックに関する私の記事を参照してください。

于 2012-05-24T19:05:41.890 に答える
2

呼び出しごとにロックする新しいオブジェクトを作成しているという事実は別として、別の根本的な問題があります。同じオブジェクトを持っていても、実際には何も保護していません。

9に初期化する線に沿ったどこかValue1

Singleton.Instance().Value1 = 9;

ここで、このコードを実行する2つのスレッドがあるとします。

public void Foo()
{
    Singleton.Instance().Value1++;

    if(Singleton.Instance().Value1==10.0)
    {
         Singleton.Instance().Value2 = 20.0;
    }
    else
    {
         Singleton.Instance().Value3 = 30.0;
    }
}

スレッドAが呼び出しValue1++、value1を10.0にインクリメントします。スレッドBが呼び出しValue1++、value1が11.0になります。スレッドAは、値value1が10.0であるかどうかをチェックします->falseを返します。スレッドAは30に設定Value3されますスレッドBValue3も30に設定されます。

これは非常に単純な例であり、外部コードは読み取りまたは書き込みの順序を保証するものではないため、プロパティをロックしても保護されません。スレッドAとスレッドBが実行される他の多くの順序が存在する可能性があり、その結果、結果は完全に異なります。

Singletonクラスのユーザーにクラス外での正しい操作を保証する責任を負わせることができたので、この動作は問題ないかもしれませんが、一般的には注意する必要があります。プロパティをロックするだけでは、読み取り/書き込みの競合は解消されません。

于 2012-05-24T19:31:40.547 に答える
1

.NET 4.0を使用していますか?ロックする代わりに、スレッドセーフなアクティビティにConCurrentコレクションを使用できます。

于 2012-05-24T19:12:04.837 に答える