锁定属性而不复制数据

本文关键字:复制 数据 属性 锁定 | 更新日期: 2023-09-27 18:28:04

我想访问其他代码可以修改的属性,并确保对它的访问是线程安全的。当然,这个问题已经被提出并得到了回答。

然而,在我的特殊情况下,我有不同的、具体的关切。首先,多线程访问/修改场景可能是一种罕见的情况,在这种情况下我不会担心性能。此外,属性本身相当大——它是一个不协调的浮点数组,大小可以达到4096乘4096,我希望尽可能少地复制它。最后,我希望类接口使用简单——这个解决方案不是这样,因为它需要用户隐式锁定一个特殊的SyncRoot。

有没有一种解决方案可以使我的属性线程安全,不需要额外的复制,并且允许客户端使用getter(setter是私有的),而不必记住锁定任何东西?

锁定属性而不复制数据

如果您想使用方便,.NET提供了内置的线程安全集合类,可以为您处理锁定。

http://msdn.microsoft.com/en-us/library/dd997305%28v=vs.110%29.aspx

你可以有

ConcurrentBag<float[]>

如果你自己滚动,我更担心将来会出现无意的死锁,而不是性能。当你开始在课外打开锁时,死锁是一个非常真实的风险。

引用操作是原子操作。因此,如果您确保使用捕获的实例,并且集合本身是不可变(其元素不会以任何方式更改),则仅从集合读取是线程安全的。

ICollection<SomeType> SomeProperty { get; set; }
// good
var property = SomeProperty; // capture
var a = property[1] + ...
// not so good
for(int i = 0; i < SomeProperty.Count; i++) // Count may be taken from new instance
{
    var a = SomeProperty[i]; // really bad
    ...
}
// bad
if(SomeProperty != null) ...

如果要设置新集合,请先填充,然后再设置。如果您只想更改一个元素-创建新的集合,请填充并设置。

void AddItem(SomeType item)
{
    var collection = new ICollection<SomeType>(SomeProperty); // copy old content
    collection.Add(item);
    SomeProperty = collection;
}

你也应该只有一个作家。多个至少需要某种同步:AddItem()中的lock

IDisposable元素存在问题。但这种想法(捕获+不可变)对于具有多个读取器和罕见写入器的场景中的简单类型应该非常有效,因为不需要同步。