基本的算术运算线程安全吗?
例如,如果对全局变量进行++
操作,将从不同的线程修改,是否需要锁定它?
例如
void MyThread() // can have many running instances
{
aGlobal++;
}
或应该是
void MyThread()
{
lock( lockerObj)
{
aGlobal++;
}
}
答案 0 :(得分:8)
The spec总结得非常好。第5.5节“变量引用的原子性”:
以下数据类型的读写是原子的:bool,char, byte,sbyte,short,ushort,uint,int,float和reference类型。在 添加,读取和写入具有基础类型的枚举类型 以前的列表也是原子的。读写其他类型的, 包括long,ulong,double和decimal,以及用户定义的 类型,不保证是原子的。除了图书馆 为此目的而设计的功能,不保证原子 read-modify-write,例如在递增或递减的情况下。
结论:
i++
)从不原子Interlocked
类方法在尚未保证的情况下实现原子性如果Interlocked
功能不够,除了使用同步原语外没有其他选择,例如Monitor.Enter
(编译器也通过lock
语句公开)。
答案 1 :(得分:2)
独立读写在大多数类型上都是原子的(不是更长的类型,通常是64位+)。但你想要的是阅读,改变,然后原子地写 - 这绝对是不原子。
如果您需要增加一个值,则System.Threading.Interlocked
类会有静态Increment
和Decrement
个动作。
如果您需要执行更复杂的求和,则使用lock
或其他构造进行同步是唯一的方法。这或者使消息系统中的内容不可变,因此您不会遇到任何共享数据访问问题,但除非是为前期设计,否则通常无法实现。
答案 2 :(得分:0)
两者都没有...你应该选择System.Threading.Interlocked.Increment(ref int location)
。这是无锁的,因为它确保处理器按照所需顺序执行读取和写入(指令 - 原子) - 而不使用System.Threading.Interlocked.Increment
为处理器提供重新排序指令的机会。
做大锤(或者没有其他可能性,因为你可能正在做大量的操作),你也可以使用lock
- 但即使在这些情况下我宁愿选择System.Threading.ReaderWriterLockSlim
代替。
btw - a nice read!