我想访问可以被其他代码修改的属性,并确保对它的访问是线程安全的。当然,这个问题已经asked and answered。
然而,在我的特殊情况下,我有不同的具体问题。首先,多线程访问/修改方案可能是一个罕见的场合,在这种情况下我不担心性能。此外,该属性本身相当大 - 它是一个震荡的浮动数组,可以达到4096 x 4096的大小,我想尽可能少复制它。最后,我希望类接口易于使用 - this solution不是,因为它要求用户隐式锁定特殊的SyncRoot。
是否有一个解决方案可以使我的属性线程安全,不需要额外的复制,并允许客户端使用getter(setter是私有的)而不必记住锁定任何内容?
答案 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
元素存在问题。但是这个想法(捕获+不可变)对于具有多个读者和稀有编写者的场景中的简单类型应该非常好用,因为不需要同步。