如何执行这种特殊类型的锁定?

时间:2012-11-29 17:28:08

标签: c# locking

我有以下代码:

    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,上述查询会发生什么?

锁定此代码是没有任何好处的,因为此查询实际上稍后会执行(除非我立即将其转换为列表)。

3 个答案:

答案 0 :(得分:1)

您可以立即将其转换为列表(可能是最好的 - )

您可以在与缓存刷新锁同步的DistributorBackpressure44中获取锁定。您可能希望包含一个锁定和解锁的访问者;在立即使用结果时使用解锁的访问器,在延迟执行情况下使用访问器时使用锁定的访问器。

请注意,如果缓存刷新会改变列表_distributorBackpress44,即使它只是替换了引用的列表,即使这样也行不通。

答案 1 :(得分:1)

如果您的设计可以容忍它,您可以使用此代码确保快照级别隔离,并完全避免锁定。但是,您需要执行以下操作:

  1. DistributorBackpressure44Cache返回ReadOnlyCollection<T>,这样就明确了你不应该改变这些数据。

  2. 确保副本上出现_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模式?)会更清晰。但我不知道这是多么可行(即将查询代码放入另一个类并传入参数)。代替更高级的东西,上述解决方案应该有效,只要您始终记得每次读/写此对象时都要锁定()。