使用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
声明中得到了错字……