我对C#的理解说(感谢Jeff Richter和Jon Skeet),任务是"原子的".什么不是当我们混合读写(递增/递减),因此我们需要使用Interlocked上的方法.如果只有Read&assign,那么这两个操作都是原子的吗?
public class Xyz
{
private volatile int _lastValue;
private IList<int> AvailableValues { get; set; }
private object syncRoot = new object();
private Random random = new Random();
//Accessible by multiple threads
public int GetNextValue() //and return last value once store is exhausted
{
//...
var count = 0;
var returnValue = 0;
lock (syncRoot)
{
count = AvailableValues.Count;
}
if (count == 0)
{
//Read... without locking... potential multiple reads
returnValue = _lastValue;
}
else
{
var toReturn = random.Next(0, count);
lock (syncRoot)
{
returnValue = AvailableValues[toReturn];
AvailableValues.RemoveAt(toReturn);
}
//potential multiple writes... last writer wins
_lastValue = returnValue;
}
return returnValue;
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 18
我对C#的理解说(感谢Jeff Richter和Jon Skeet),任务是"原子的".
一般来说,分配不是原子的.C#规范仔细调出了保证原子的东西.见5.5节:
以下数据类型的读取和写入是原子的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型.此外,在先前列表中具有基础类型的枚举类型的读取和写入也是原子的.其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是原子的.
(重点补充.)
如果只有Read&assign,那么这两个操作都是原子的吗?
同样,第5.5节回答了你的问题:
不保证原子读 - 修改 - 写
Mar*_*ell 11
volatile实际上与缓存(寄存器等)更相关; 与volatile您知道该值实际写入到/读取从内存中直接(这实际上不是总是这样以其他方式).这允许不同的线程立即看到彼此的更新.指令重新排序还有其他微妙的问题,但这很复杂.
这里有两个"原子"的含义:
Doubles的一半,产生一个从未存在过的数字)"本身"取决于价值的大小; 可以在一次操作中更新吗?读/写对更多地与隔离有关 - 即防止丢失更新.
在您的示例中,两个线程可以读取相同的内容_lastValue,进行计算,然后(单独)更新_lastValue.其中一个更新将丢失.实际上,我希望你想要一个lock超过读/写过程的持续时间.
使用volatile关键字不会使访问线程安全,它只是确保从内存中读取变量,而不是从可能从先前读取缓存的寄存器中读取.某些体系结构会进行此优化,这会导致在您将多个线程写入同一变量时使用过时值.
为了正确同步访问,您需要拥有更宽的锁:
public class Xyz
{
private volatile int _lastValue;
private IList<int> AvailableValues { get; set; }
private object syncRoot = new object();
private Random rand = new Random();
//Accessible by multiple threads
public int GetNextValue() //and return last value once store is exhausted
{
//...
lock (syncRoot)
{
var count = AvailableValues.Count;
if(count == 0)
return _lastValue;
toReturn = rand.Next(0, count);
_lastValue = AvailableValues[toReturn];
AvailableValues.RemoveAt(toReturn);
}
return _lastValue;
}
}
Run Code Online (Sandbox Code Playgroud)
如果性能是一个问题,您可能需要考虑使用LinkedList for AvailableValues,因为它支持O(1)删除操作.
| 归档时间: |
|
| 查看次数: |
2841 次 |
| 最近记录: |