C# 只读集合和线程-此代码安全吗?

C# 只读集合和线程-此代码安全吗?,c#,locking,C#,Locking,我有一个线程较多的应用程序,其只读集合如下: internal static ReadOnlyCollection<DistributorBackpressure44> DistributorBackpressure44Cache { get { return _distributorBackpressure44; } set { _distributorBackpressure44 = value; }

我有一个线程较多的应用程序,其只读集合如下:

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

我假设我所做的是线程安全的,不需要进行任何锁定?我不确定的是,如果在另一个线程中替换集合的同一时间发生上述查询,会发生什么情况?

引用分配是原子的,因此是的,它是线程安全的。但前提是您不依赖于数据在写入后立即准备好读取。这是因为缓存的缘故,您可能希望加入一个
volatile
,以防止出现这种情况


另请参见。

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


随机性会给你带来麻烦。请注意,这与集合是否为只读无关。线程使用过时的值也许是可以的,但这并不常见。最重要的是你没有提到这没关系,所以你可能还没有考虑到后果。你需要仔细考虑一下。在属性getter和setter中,您自己无法对此做任何事情,线程必须在它们之间进行协商。这就是线程化的困难所在,并且让您彻底分析代码中共享可变数据的位置变得非常重要。类似于此属性。

在您的情况下,听起来好像不会有问题,但是如果
ReadOnlyCollection
正在包装的基础集合发生更改,您可能会遇到问题

例如,以下代码块将抛出一个带有消息“Collection was modified;enumeration operation may not execute”(集合已修改;枚举操作可能无法执行)的
InvalidOperationException,因为在另一个线程上枚举时,基础
列表
已从中移除一个项

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);
var numbers=newlist(){1,2,3,4,5};
var readOnly=新的ReadOnlyCollection(数字);
ThreadPool.QueueUserWorkItem(x=>{
foreach(只读中的整数)
{
控制台写入线(编号);
睡眠(300);
}
});
睡眠(150);
数字。删除(2);

我不太清楚你的确切意思。但是,如果您的意思是数据的某些读取器可能具有“旧”副本,而某些读取器可能具有“新”副本,则这是可以接受的。
foreach (DistributorBackpressure44 distributorBackpressure44 in CicApplication.DistributorBackpressure44Cache.Where(row => row.Coater == coater && row.CoaterTime >= targetTime).ToList())
{
 ...
 ...
}
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);