4

I think a static object is shared across multiple threads. However, I got a high CPU issue on one of my site, so I took a windbg dump and very surprised, I see this:

enter image description here

We can see that there are 10 instances of a class called ConnectionMultiplexer. But my code creates ConnectionMultiplexer as a static object. This should mean that only one instance be created for all the threads. So how come windbg is showing multiple instances?

This is my code to create a redis connection

public static class CacheConnection
    {
        private static StackExchangeRedisCacheClient _newconnectionDb;

        public static StackExchangeRedisCacheClient NewConnectionDb
            => _newconnectionDb ?? (_newconnectionDb = NewRedisConnection());

        private static IDatabase _connectionDb;

        public static IDatabase ConnectionDb => _connectionDb ?? (_connectionDb = RedisConnection());

        private static StackExchangeRedisCacheClient NewRedisConnection()
        {
            var serializer = new NewtonsoftSerializer();
            return new StackExchangeRedisCacheClient(Connection, serializer);
        }

        private static IDatabase RedisConnection()
        {
            var cacheDatabase = Connection.GetDatabase();
            return cacheDatabase;
        }

        public static ConnectionMultiplexer Connection => LazyConnection.Value;

        private static readonly Lazy<ConnectionMultiplexer> LazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(
            System.Configuration.ConfigurationManager.AppSettings["CacheConnectionString"]), LazyThreadSafetyMode.PublicationOnly);
    }
daxu
  • 3,514
  • 5
  • 38
  • 76
  • Regarding your first sentence: Any object is on the heap and the heap is available to any thread. So the fact that it is static does not matter to that. – Thomas Weller Sep 28 '17 at 20:28

1 Answers1

5

ConnectionMultiplexer is actually a readonly (get) property using the new C# 7 short syntax => that returns LazyConnection.Value everytime you access it.

Then you use LazyThreadSafetyMode.PublicationOnly which is defined as this in MSDN (https://msdn.microsoft.com/en-us/library/system.threading.lazythreadsafetymode(v=vs.110).aspx)

When multiple threads try to initialize a Lazy instance simultaneously, all threads are allowed to run the initialization method (or the default constructor, if there is no initialization method). The first thread to complete initialization sets the value of the Lazy instance. That value is returned to any other threads that were simultaneously running the initialization method, unless the initialization method throws exceptions on those threads. Any instances of T that were created by the competing threads are discarded. If the initialization method throws an exception on any thread, the exception is propagated out of the Lazy.Value property on that thread. The exception is not cached. The value of the IsValueCreated property remains false, and subsequent calls to the Value property, either by the thread where the exception was thrown or by other threads, cause the initialization method to run again. If the initialization method recursively accesses the Value property of the Lazy instance, no exception is thrown.

This means that if multiple threads try to access it in the same time they will each create its own instance although you'll end up using the first one created regardless of the thread (but the instances are still there).

What you actually need is LazyThreadSafetyMode.ExecutionAndPublication but this may introduce deadlocks.

If you don't need this to be Lazy you can use one of the singleton pattern implementations suggested by Jon Skeet in his book C# In Depth

You can find them here http://csharpindepth.com/Articles/General/Singleton.aspx

Mihail Shishkov
  • 14,129
  • 7
  • 48
  • 59