我有以下代码:
var sequence = from row in CicApplication.DistributorBackpressure44Cache
where row.Coater == this.Coater && row.IsDistributorInUse
select new GenericValue
{
ReadTime = row.CoaterTime.Value,
Value = row.BackpressureLeft
};
this.EvaluateBackpressure(sequence, "BackpressureLeftTarget");
DistributorBackpressure44Cache的定义如下:
internal static List<DistributorBackpressure44> DistributorBackpressure44Cache
{
get
{
return _distributorBackpressure44;
}
}
这是一个高度线程化的应用程序的一部分,其中DistributorBackpressure44Cache可以在一个线程中刷新,并在另一个线程中查询,如上所示。上面的变量'sequence'是一个IEnumerable,它被传递给所示的方法,然后在实际执行之前可能传递给其他方法。我担心的是这个。如果在实际执行查询时刷新(清除并重新填充)DistributorBackpressure44Cache,上述查询会发生什么?
锁定此代码是没有任何好处的,因为此查询实际上稍后会执行(除非我立即将其转换为列表)。
答案 0 :(得分:1)
您可以立即将其转换为列表(可能是最好的 - )
或
您可以在与缓存刷新锁同步的DistributorBackpressure44中获取锁定。您可能希望包含一个锁定和解锁的访问者;在立即使用结果时使用解锁的访问器,在延迟执行情况下使用访问器时使用锁定的访问器。
请注意,如果缓存刷新会改变列表_distributorBackpress44,即使它只是替换了引用的列表,即使这样也行不通。
答案 1 :(得分:1)
如果您的设计可以容忍它,您可以使用此代码确保快照级别隔离,并完全避免锁定。但是,您需要执行以下操作:
让DistributorBackpressure44Cache
返回ReadOnlyCollection<T>
,这样就明确了你不应该改变这些数据。
确保副本上出现_distributorBackpressure44
的任何突变,并在完成后导致原子分配回_distributorBackpressure44
。
var cache = _distributorBackpressure44.ToList();
this.RefreshCache(cache); // this assumes you *need* to know
// about the structure of the old list
// a design where this is not required
// is preferred
_distributorBackpressure44 = cache; // some readers will have "old"
// views of the cache, but all readers
// from some time T (where T < Twrite)
// will use the same "snapshot"
答案 2 :(得分:0)
在不了解您的架构选项的情况下,您可以做类似的事情。
lock(CicApplication.DistributorBackpressure44Cache)
{
var sequence = from row in CicApplication.DistributorBackpressure44Cache
where row.Coater == this.Coater && row.IsDistributorInUse
select new GenericValue
{
ReadTime = row.CoaterTime.Value,
Value = row.BackpressureLeft
};
}
this.EvaluateBackpressure(sequence, "BackpressureLeftTarget");
然后在您执行清除/更新的代码中,您将拥有类似的内容。
lock(CicApplication.DistributorBackpressure44Cache)
{
var objCache = CicApplication.DistributorBackpressure44Cache
objCache.Clear();
// code to add back items here
// [...]
}
拥有一个控制缓存周围所有内容的中心类(可能是Singleton模式?)会更清晰。但我不知道这是多么可行(即将查询代码放入另一个类并传入参数)。代替更高级的东西,上述解决方案应该有效,只要您始终记得每次读/写此对象时都要锁定()。