// 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 per loop. There are many threads iterating this loop and based on the key
they are looking for, a lazy instance is created and returned.
lazyObject
should not be created more that one time. Although Lazy
class is for doing so and despite of the used lock, under high threading I have more than one instance created (I track this with a Interlocked.Increment
on a volatile
static int
and log it somewhere). The problem is I don't have access to definition of Lazy
and MEF
defines how the Lazy
class create objects. I should notice the CompositionContainer
has a thread-safe option in constructor which is already used.
My questions:
1) Why the lock doesn't work ?
2) Should I use an array of locks instead of one lock for performance improvement ?
Is the default constructor of
T
in yourLazy
complex? MEF usesLazyThreadSafetyMode.PublicationOnly
which means each thread accessing the unitialisedLazy
will generate anew()
onT
until the first to complete the initialisation. That value is then returned for all threads currently accessing.Value
and their ownnew()
instances are discarded. If your constructor is complex (perhaps doing too much?) you should redefine it as doing minimal construction work and moving configuration to another method.You need to think about the method as a whole. Should you consider:
You also need to consider that if
plugins
is not read-only then you need to synchronise access to that instance too, otherwise it may be modified on another thread, causing your code to fall over.There is a specific constructor of
Lazy<T, TMetadata>
for such scenarios, where you define aLazyThreadSafetyMode
when constructing a Lazy instance... Otherwise, the lock might not work for many different reasons, e.g. if this is not the only place where theValue
property of thisLazy<T>
instance is ever accessed.Btw you got I typo in the
if
statement...