Thread-safe lazy instance using MEF

// Member Variable private static readonly object _syncLock = new object(); // Now inside a static method foreach (var lazyObject in plugins) { if ((string)lazyObject.Metadata["key"] = "something") { lock (_syncLock) { // It seems the `IsValueCreated` is not up-to-date if (!lazyObject.IsValueCreated) lazyObject.value.DoSomething(); } return lazyObject.value; } } 

Here I need synchronized access for each cycle. There are many threads repeating this cycle and based on the key that they are looking for, a lazy instance is created and returned.

lazyObject should not be created more than once. Although the Lazy class for this, and despite the lock used, has high streaming more than one instance (I track this with Interlocked.Increment on a volatile static int and write it somewhere). The problem is that I do not have access to the Lazy definition, and MEF determines how the Lazy class creates objects. I should notice that the CompositionContainer has a stream option in the constructor that is already in use.

My questions:

1) Why does the lock not work?

2) Should I use an array of locks instead of a single lock to improve performance?

+4
source share
2 answers

Is the default T constructor in your Lazy complex? MEF uses LazyThreadSafetyMode.PublicationOnly , which means that each thread accessing the unified Lazy will generate a new() on T until the first completes initialization. This value is then returned for all threads that are currently accessing .Value , and their own new() instances are discarded. If your constructor is complex (perhaps too much?), You must redefine it by doing minimal construction work and moving the configuration to another method.

You need to think about the method as a whole. If you think:

 public IPlugin GetPlugin(string key) { mutex.WaitOne(); try { var plugin = plugins .Where(l => l.Metadata["key"] == key) .Select(l => l.Value); .FirstOrDefault(); return plugin; } finally { mutex.ReleaseMutex(); } } 

It is also necessary to consider that if plugins not read-only, you also need to synchronize access to this instance, otherwise it can be changed in another thread, as a result of which your code will crash.

+4
source

For such scenarios, there is a specific Lazy<T, TMetadata> where you define LazyThreadSafetyMode when building the Lazy instance ... Otherwise, locking may not work for many reasons, for example. if this is not the only place where the Value property of this Lazy<T> instance is always available.

By the way, you have a typo in the if ...

0
source

Source: https://habr.com/ru/post/1334742/


All Articles