Are the basic arithmetic operations Thread safe?
For example, if there is ++
operation on a global variable, which will be modified from different threads, is it necessary to a lock around it?
For example
void MyThread() // can have many running instances
{
aGlobal++;
}
or should it be
void MyThread()
{
lock( lockerObj)
{
aGlobal++;
}
}
The spec sums it up very well. Section 5.5, "Atomicity of variable references":
Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.
Conclusions:
i++
) is never atomicInterlocked
class methods to achieve atomicity when it's not already guaranteedIn cases where Interlocked
functionality is not enough there is no other option than to use a synchronization primitive, such as Monitor.Enter
(which the compiler also exposes through the lock
statement).
Reads and writes independently are atomic on most types (not the longer types, usually 64bit+). But what you want is to read, change, then write atomically - this is definitely not atomic.
If you need to increment a value, there is the System.Threading.Interlocked
class with static Increment
and Decrement
actions.
If you need to do more complex sums, then synchronisation using lock
or another construct is the only way. That or make things immutable as in messaging systems so you don't get any shared data access issues, but this usually isn't attainable unless designed for upfront.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With