2

我有一个带有 ReadOnlyCollection 的重线程应用程序,如下所示:

internal static ReadOnlyCollection<DistributorBackpressure44> DistributorBackpressure44Cache
{
    get
    {
        return _distributorBackpressure44;
    }
    set
    {
        _distributorBackpressure44 = value;
    }
}

我在应用程序中有一个地方替换了这个集合(总是在一个单独的线程上),它看起来像这样:

    CicApplication.DistributorBackpressure44Cache = new ReadOnlyCollection<DistributorBackpressure44>(someQueryResults.ToList());

我在代码中有很多地方可以访问这个集合,通常是通过 Linq 查询,在许多不同的线程中。代码通常看起来像这样:

foreach (DistributorBackpressure44 distributorBackpressure44 in CicApplication.DistributorBackpressure44Cache.Where(row => row.Coater == coater && row.CoaterTime >= targetTime).ToList())
{
 ...
 ...
}

我假设我正在做的是线程安全的,不需要做任何锁定?我不确定的是,如果上面的查询发生在集合被另一个线程替换的完全相同的时间,会发生什么?

4

3 回答 3

5

引用分配是原子的,所以是的,它是线程安全的。但前提是您不依赖数据在写入后的那一刻准备好被读取。这是因为缓存,您可能需要加入 avolatile来防止这种情况。

另请参阅引用分配是原子的,那么为什么需要 Interlocked.Exchange(ref Object, Object)?.

于 2012-11-29T18:34:45.007 回答
2

这是不太可能的。在一个完全不可预测的时刻,在线程分配属性之后,其他线程将看到新的集合。他们会在此之前读取一个陈旧的值。这可能是 null 或者可能是另一个内容完全不同的集合。

随机性会给你带来麻烦。请注意,这与集合是否为只读无关。线程使用陈旧的值也许是可以的,但这并不常见。最重要的是你没有提到这没关系,所以你可能还没有考虑到后果。你需要考虑清楚这一点。在属性 getter 和 setter 中您自己无能为力,线程将不得不在它们之间进行协商。这就是使线程变得困难的原因,并且使您彻底分析代码中共享可变数据的位置非常重要。喜欢这个楼盘。

于 2012-11-29T18:50:56.353 回答
0

听起来在您的情况下这不是问题,但是如果ReadOnlyCollection包装的基础集合发生变化,您可能会遇到问题。

例如,以下代码块将抛出InvalidOperationException消息“集合已修改;枚举操作可能无法执行”,因为在另一个线程上枚举时,底层List<int>已从其中删除了一个项目。

var numbers = new List<int>() {1,2,3,4,5};
var readOnly = new ReadOnlyCollection<int>(numbers);

ThreadPool.QueueUserWorkItem(x => {
    foreach (int number in readOnly)
    {
        Console.WriteLine(number);
        Thread.Sleep(300);
    }
});

Thread.Sleep(150);
numbers.Remove(2);
于 2014-05-27T14:29:25.057 回答