C# Singleton thread safe

爷,独闯天下 提交于 2019-12-12 10:32:42

问题


I have a singleton class similar to this

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?
        }
    }
}

The CallMe method will be called by web service:

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

The questions: 1) Is the m_cacheObjects is thread safe? what happen if the m_cacheObjects is changed(because of the timer) during the loop interation (in the CallMe() )?

2) Is a new thread will be created when the Webservice CallMeWebService() is being called?


回答1:


1: No, a static list is not automatically thread-safe; you must protect m_cacheObjects manually

2: That is an implementation detail; at first glance it looks like it exposes itself as a sync method, but how it does that is entirely up to it

Actually, your static initialization isn't thread-safe either; I could brute-force a scenario where two different Singleton instances were used. It would take repetition to produce it, but it would happen.

Frankly, unless you have a really good reason not to, the simplest but safest singleton pattern is simply:

private static readonly Singleton m_instance = new Singleton();



回答2:


I'd suggest you have aread on Jon Skeets article on how to create thread safe singletons over at http://csharpindepth.com/Articles/General/Singleton.aspx




回答3:


//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;
    }
}

Explain:

[MethodImpl(MethodImplOptions.Synchronized)] This will tell the compiler that the access to "Instance" is "Synchronized" so the system take care about the calls to this Parameter.

This is Thread-Safe.

EDIT: (Also, the "Lock()" examples are not safe! Coz, u can disable the thread Safety with "Monitor.Exit(Singleton);")




回答4:


This is a pretty good resource on how to implement the singleton pattern in a thread safe way: 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;
      }
   }
}

This simply makes sure that there will never be more than one instance. You also need to apply locking for your custom method.

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



回答5:


It is not thread safe.

I believe i would use a lock in both 'MyTimerCallBack' and 'CallMe' methods




回答6:


1) No, m_cacheObjects is not thread-safe.

2) Yes, new thread will be created (well, it may not be new thread but rather thread taked from thread-pool).

You'll need to protect m_cacheObjects with lock statement. Also, in the CallMe method I'd recommend to create a local copy of m_cacheObjects:

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

New CallMe method:

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

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

And updated MyTimerCallBack method:

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

And please also implement thread-safe Singleton (read other answers for details).



来源:https://stackoverflow.com/questions/11665102/c-sharp-singleton-thread-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!