首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >阵列的ReaderWriterLock

阵列的ReaderWriterLock
EN

Stack Overflow用户
提问于 2012-08-14 18:45:06
回答 2查看 2K关注 0票数 4

我有一个数组,它代表一个清单,有将近50个元素(项目:一些客户对象),我需要一个readerwritelock (好的,我想一个简单的锁也足够了)。它应该同时支持引用更改和值更改。

由于读写数组的不同位置是线程安全的(Proof),我希望确保同一数组位置上的多个读/写操作也是线程安全的。

我当然可以创建50个读写锁,但我不想这样;)有没有办法把它归档?(我知道ConcurrentList/Dictionary/等,但我想要一个数组...)

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-14 18:57:41

如果您要替换数组中的引用,那么这已经是安全的,因为引用交换本质上是原子的。因此,您可以使用:

代码语言:javascript
复制
var val = arr[index];
// now work with val

代码语言:javascript
复制
var newVal = ...
arr[index] = newVal;

完全安全,至少在避免被撕裂的引用方面是这样。因此,一个实用的选择是使用使对象成为不可变的,并使用上面的方法。如果您需要更改该值,请获取一个本地副本,基于该副本创建一个新版本,然后交换它们。如果丢失更新是一个问题,那么可以非常成功地使用Interlocked.CompareExchange和re-apply循环(即不断重新应用您的更改,直到您“赢”为止)。这就避免了任何锁定的需要。

但是,如果你改变了单个对象,那么游戏就会改变。你可以让对象在内部是线程安全的,但这通常并不美观。你可以为所有的对象设置一个锁。但是如果你想要粒度锁,那么你将需要多个锁。

我的建议是:让对象不可变,只使用原子引用交换技巧。

票数 5
EN

Stack Overflow用户

发布于 2012-08-14 18:57:15

首先,您可能不需要任何锁。使用一种类型的数组进行读写操作本身就是线程安全的(但您可能希望设置内存屏障以避免陈旧的读操作)。

也就是说,就像整数的x = 34是线程安全的,但x++不是,如果你的写依赖于当前值(因此是读和写),那么那就不是线程安全。

如果您确实需要锁,但又不想要多达50个锁,那么您可以使用条纹。首先设置您的条纹锁(对于较小的示例代码,我将使用简单的锁而不是ReaderWriterSlim,原理相同):

代码语言:javascript
复制
var lockArray = new object[8];
for(var i =0; i != lockArray.Length; ++i)
  lockArray[i] = new object();

然后当你要使用它的时候:

代码语言:javascript
复制
lock(lockArray[idx % 8])
{
  //operate on item idx of your array here
}

它平衡了一个锁的简单性和大小,以及每个元素使用一个锁的内存使用情况。

如果一个元素上的操作依赖于另一个元素的操作,如果你需要调整数组的大小,或者任何其他需要有多个锁的情况,那么最大的困难就来了。通过始终以相同的顺序获取锁,可以避免许多死锁情况(因此,需要多个锁的其他线程不会在持有所需锁的同时尝试获取已有的锁),但在这种情况下需要非常小心。

您还希望确保在处理索引3和索引11时,避免两次锁定对象3(我想不出这种特定的递归锁定会出错的方式,但为什么不直接避免它,而是必须证明递归锁定是安全的情况之一呢?)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11950628

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档