1

我有以下代码:

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

锁定这段代码并没有任何好处,因为这个查询实际上会在稍后的某个时间执行(除非我要立即将其转换为列表)。

4

3 回答 3

1

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

或者

您可以在与缓存刷新锁同步的 DistributorBackpressure44 的 get 中放置一个锁。您可能想要包括一个锁定和解锁的访问器;当要立即使用结果时使用未锁定的访问器,当要在延迟执行情况下使用访问器时使用锁定的访问器。

请注意,如果缓存刷新使列表 _distributorBackpress44 发生变异,即使它仅替换引用的列表也不会起作用。

于 2012-11-29T17:38:49.040 回答
1

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

  1. DistributorBackpressure44Cache改为返回 a ,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"
    
于 2012-11-29T17:39:27.367 回答
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
    // [...]
}

拥有一个控制缓存周围所有内容的中心类(也许是单例模式?)会更干净。但我不知道这是多么可行(即将查询代码放入另一个类并传入参数)。只要您在每次读/写此对象时始终记得 lock() ,上述解决方案就可以代替更高级的东西。

于 2012-11-29T17:37:02.860 回答