// 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;
}
}
这里我需要每个循环同步访问。有许多线程在迭代这个循环并基于它们正在寻找的key
,创建并返回一个惰性实例。
lazyObject
不应该多次创建。虽然Lazy
类是这样做的,尽管使用了锁,但在高线程下我创建了多个实例(我在Interlocked.Increment
{{1}上使用volatile
进行跟踪并将其记录在某个地方)。问题是我无法访问static int
的定义,而Lazy
定义了MEF
类如何创建对象。我应该注意Lazy
在构造函数中有一个已经使用的线程安全选项。
我的问题:
1)为什么锁不起作用?
2)我应该使用一系列锁而不是一把锁来提高性能吗?
答案 0 :(得分:4)
T
复合体中Lazy
的默认构造函数是? MEF使用LazyThreadSafetyMode.PublicationOnly
,这意味着访问单元化Lazy
的每个线程将在new()
上生成T
,直到第一个完成初始化。然后为当前访问.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
不是只读的,那么您也需要同步对该实例的访问权限,否则可能会在另一个线程上进行修改,从而导致代码崩溃。
答案 1 :(得分:0)
对于这种情况,有Lazy<T, TMetadata>
的特定构造函数,在构造Lazy实例时定义LazyThreadSafetyMode
...否则,锁定可能由于许多不同的原因而无法工作,例如如果这不是唯一访问此Value
实例的Lazy<T>
属性的地方。
顺便说一句,你在if
陈述中得到了错字......