使用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; } } 

在这里,我需要每个循环同步访问。 有很multithreading迭代这个循环,并根据它们正在寻找的key ,创建并返回一个惰性实例。

lazyObject应该lazyObject创建lazyObject 。 虽然Lazy类是这样做的,尽管使用了锁,但在高线程下我创建了多个实例(我在一个volatile static int上使用Interlocked.Increment跟踪它并将其记录到某处)。 问题是我无法访问Lazy定义,而MEF定义了Lazy类如何创建对象。 我应该注意到CompositionContainer在构造函数中有一个已经使用过的线程安全选项。

我的问题:

1)为什么锁不起作用?

2)我应该使用一系列锁而不是一个锁来提高性能吗?

Lazy复合体中T的默认构造函数吗? MEF使用LazyThreadSafetyMode.PublicationOnly ,这意味着访问单元化Lazy每个线程将在T上生成new() ,直到第一个完成初始化。 然后为当前访问的所有线程返回该值.Value和它们自己的new()实例将被丢弃。 如果您的构造函数很复杂(可能做得太多了?),您应该将其重新定义为执行最少的构造工作并将配置移动到另一个方法。

你需要考虑整个方法。 你应该考虑:

 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(); } } 

您还需要考虑如果plugins不是只读的,那么您也需要同步对该实例的访问,否则可能会在另一个线程上修改,导致代码崩溃。

对于此类场景,有一个特定的Lazy构造函数,您可以在构造Lazy实例时定义LazyThreadSafetyMode …否则,锁定可能由于许多不同原因而无法工作,例如,如果这不是唯一的地方访问此Lazy实例的Value属性。

顺便说一句,你在if声明中得到了错字……