我有一个数组,代表库存,其中有近50个元素(物品:一些自定义对象),我需要为它使用读写锁(好的,我认为一个简单的锁也足够了)。它应支持引用更改和值更改。
由于对数组的不同位置进行读写是线程安全的(证明),我希望确保对同一数组位置的多个读/写操作也是线程安全的。
我肯定可以创建50个读写锁,但我不想这样做;) 有没有办法实现这个目标?(我知道 ConcurrentList/Dictionary 等,但我想要一个数组...)
谢谢
我有一个数组,代表库存,其中有近50个元素(物品:一些自定义对象),我需要为它使用读写锁(好的,我认为一个简单的锁也足够了)。它应支持引用更改和值更改。
由于对数组的不同位置进行读写是线程安全的(证明),我希望确保对同一数组位置的多个读/写操作也是线程安全的。
我肯定可以创建50个读写锁,但我不想这样做;) 有没有办法实现这个目标?(我知道 ConcurrentList/Dictionary 等,但我想要一个数组...)
谢谢
如果您要替换数组中的引用,那么这已经是安全的了,因为引用交换本质上是原子操作。因此您可以使用以下代码:
var val = arr[index];
// now work with val
并且
var newVal = ...
arr[index] = newVal;
Monitor
是一个实例类,并且您需要锁定一个明确的 Monitor
实例——这将使锁定变得不那么棘手。对于粒度锁定,老实说,我更喜欢您的分段选项。 - Marc Gravellx=34
是线程安全的,但x++
则不是,如果你的写入依赖于当前值(因此需要一次读取和一次写入),那么它就不是线程安全的。ReaderWriterSlim
,但相同的原理适用)。var lockArray = new object[8];
for(var i =0; i != lockArray.Length; ++i)
lockArray[i] = new object();
lock(lockArray[idx % 8])
{
//operate on item idx of your array here
}
在一个锁用于所有元素的简单性和大小与每个元素都有一个锁的内存使用之间需要平衡。
如果一个元素的操作依赖于另一个元素的操作,如果你需要调整数组的大小或任何其他需要多个锁的情况,那么问题就来了。始终按相同的顺序获取锁可以避免很多死锁情况(这样不会有其他需要多个锁的线程尝试获取你已经拥有的锁并持有你需要的锁),但在这些情况下需要非常小心。
您还需要确保,如果您正在处理第3个索引和第11个索引,您要避免两次锁定对象3(我想不出这种特定递归锁定会出什么问题,但为什么不避免它,而不是必须证明它是安全的情况之一?)
arr[12] = newObj;
?还是arr[12].Foo = "abc";
? - Marc Gravell