锁定属性而不复制数据

时间:2014-10-28 14:54:08

标签: c# properties thread-safety

我想访问可以被其他代码修改的属性,并确保对它的访问是线程安全的。当然,这个问题已经asked and answered

然而,在我的特殊情况下,我有不同的具体问题。首先,多线程访问/修改方案可能是一个罕见的场合,在这种情况下我不担心性能。此外,该属性本身相当大 - 它是一个震荡的浮动数组,可以达到4096 x 4096的大小,我想尽可能少复制它。最后,我希望类接口易于使用 - this solution不是,因为它要求用户隐式锁定特殊的SyncRoot。

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

2 个答案:

答案 0 :(得分:0)

如果您想要易用,.NET提供了内置的线程安全集合类来处理锁定。

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

你可以有一个

ConcurrentBag<float[]>

如果你自己动手,我会更担心未来的意外死锁而不是性能。当你开始在课堂外开放锁定时,死锁是一个非常现实的风险。

答案 1 :(得分:0)

参考操作为atomic。因此,如果确保使用捕获的实例并且集合本身是 immutable (它的元素不会通过任何方式改变),那么仅从集合读取是线程安全的。

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

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

IDisposable元素存在问题。但是这个想法(捕获+不可变)对于具有多个读者和稀有编写者的场景中的简单类型应该非常好用,因为不需要同步。