简体   繁体   中英

How to make singleton members threadsafe

Let's say I have the following singleton:

public sealed class singleton
{
// fields, creation, etc.
private static IList<SomeObjectType> _objects = new List<SomeObjectType>();
private ManualResetEvent _updateCompleted = new ManualResetEvent(true);

private bool RefreshRequired()
{
    //true if records in DB newer than the objects in the list
}

private void RefreshList()
{
    _updateCompleted.Reset();

    //code to refresh the list

    _updateCompleted.Set();
}

public IList<SomeObjectType> Objects
{
    get
    {
        _updateCompleted.Wait();

        if (RefreshRequired())
            RefreshList();

        return _objects;
    }
}

..

This way I am trying to achieve that data stored in the list is always up to date before any client reads it. This mechanism is very simple, but it is working well so far. However, obviously it is not sufficient for multithreading scenarios. If there were multiple threads accessing the Objects-Member, I wanted only the first one to check if data is up to date and, then update the List if necessary. While the refresh is in progress, all other threads should be forced to wait BEFORE even checking if an refresh is required. I have read much ablut locks, BlockedCollections, and ManualResetEvents, but I am not sure about which concept to use.

Could you explain which one you would choose and how you would solve the described task?

Best answer i can suggest is found here: http://csharpindepth.com/Articles/General/Singleton.aspx

Since I'll get yelled at by the masses if only posting a link, here are some samples taken from the article to ponder. The article largely has to do with performance, and appropriateness so please read it's descriptions of these samples.

As far as your Refresh method, the others commented on that fairly well. It's just as important knowing how it's intended to be consumed.

Hopefully the article gives you some food for thought.

Simple thread safety...

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

    Singleton()
    {
    }

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

Thread-safe without using locks...

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

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
    }

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

Fully lazy instantiation...

public sealed class Singleton
{
    private Singleton()
    {
    }

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

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
}

Using .NET 4's Lazy type...

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM