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);