10

これに似たシングルトンクラスがあります

public class Singleton
{
    private static Singleton m_instance;
    private Timer m_timer;
    private static List<CustomObject> m_cacheObjects;

    private Singleton()
    {    
        m_cacheObjects = new List<CustomObject>();
        m_timer= new Timer(MyTimerCallBack, 
                           null, 
                           TimeSpan.FromSeconds(60), 
                           TimeSpan.FromSeconds(60));           
    }

    public static Singleton Instance
    {
        get
        {
            if (m_instance == null)
            {
                m_instance = new Singleton();
            }
            return m_instance;
        }
    }

    private void MyTimerCallBack(object state)
    {
        //******** Update the list by interval here ******************

        m_cacheObjects = UpdateTheList();
    }

    public void CallMe()
    {
        foreach (CustomObject obj in m_cacheObjects)
        {
            // do something here based on obj

            // The question is, does the m_cacheObjects is thread safe??
            // what happen if the m_cacheObjects is changed
            // during the loop interation?
        }
    }
}

CallMe メソッドは Web サービスによって呼び出されます。

  [WebMethod]
    public void CallMeWebService()
    {
        Singleton.Instance.CallMe();
    }

質問: 1) m_cacheObjects はスレッドセーフですか? m_cacheObjects が (タイマーのために) ループの反復中に ( CallMe() で) 変更された場合はどうなりますか?

2) Web サービスの CallMeWebService() が呼び出されると、新しいスレッドが作成されますか?

4

6 に答える 6

8

1: いいえ、静的リストは自動的にスレッドセーフではありません。m_cacheObjects手動で保護する必要があります

2: これは実装の詳細です。一見、同期メソッドとして公開されているように見えますが、それをどのように行うかは完全にあなた次第です

実際、静的初期化もスレッドセーフではありません。Singleton2 つの異なるインスタンスが使用されているシナリオをブルート フォースすることができました。それを生み出すには繰り返しが必要ですが、それは起こります。

率直に言って、本当に正当な理由がない限り、最も単純だが最も安全なシングルトン パターンは次のとおりです。

private static readonly Singleton m_instance = new Singleton();
于 2012-07-26T08:20:33.050 に答える
6
//using System.Runtime.CompilerServices;

private static volatile Singelton _instance;

public static Singelton Instance
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get
    {
        if (_instance == null)
        {
            _instance = new Singelton();
        }
        return _instance;
    }
}

説明:

[MethodImpl(MethodImplOptions.Synchronized)]これにより、「インスタンス」へのアクセスが「同期」されていることがコンパイラに通知されるため、システムはこのパラメータの呼び出しを処理します。

これはスレッドセーフです。

EDIT:(また、「Lock()」の例は安全ではありません!Coz、uは「Monitor.Exit(Singleton);」でスレッドの安全性を無効にすることができます)

于 2014-09-06T10:43:49.563 に答える
5

http://csharpindepth.com/Articles/General/Singleton.aspxで、スレッド セーフなシングルトンの作成方法に関する Jon Skeets の記事を読んだことをお勧めします。

于 2012-07-26T08:22:40.373 に答える
4

これは、シングルトン パターンをスレッド セーフな方法で実装する方法に関する非常に優れたリソースです: http://msdn.microsoft.com/en-us/library/ff650316.aspx

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
     if (instance == null) 
     {
        lock (syncRoot) 
        {
           if (instance == null) 
          instance = new Singleton();
        }
     }

     return instance;
      }
   }
}

これにより、複数のインスタンスが存在しないことが保証されます。また、カスタム メソッドにロックを適用する必要があります。

public void CallMe()
{
    lock (syncRoot) 
    {
        foreach (CustomObject obj in m_cacheObjects)
        {
            // do something here based on obj
        }
    }
}
于 2012-07-26T08:19:27.510 に答える
0

1) いいえ、m_cacheObjectsスレッドセーフではありません。

2) はい、新しいスレッドが作成されます (新しいスレッドではなく、スレッドプールから取得されたスレッドである可能性があります)。

ステートメントで保護m_cacheObjectsする必要があります。lockまた、CallMe メソッドでは、次のローカル コピーを作成することをお勧めしますm_cacheObjects

// create new field syncRoot
private static readonly object syncRoot = new object();

新しい CallMe メソッド:

List<CustomObject> localCopy;
lock (syncRoot)
{
    localCopy = new List<CustomObject>(m_cacheObjects);
}

foreach (var nextObject in localCopy)
{
// Do some work
}

そして更新されたMyTimerCallBack方法:

lock (syncRoot)
{
    m_cacheObjects = UpdateTheList();
}

また、スレッドセーフなシングルトンも実装してください(詳細については他の回答を読んでください)。

于 2012-07-26T08:33:42.710 に答える
0

スレッドセーフではありません。

「MyTimerCallBack」メソッドと「CallMe」メソッドの両方でロックを使用すると思います

于 2012-07-26T08:21:33.827 に答える