Are +=, |=, &= etc atomic? [duplicate]
Are the "modify" operators like +=
, |=
, &=
etc atomic?
I know ++
is atomic (if开发者_JAVA百科 you perform x++;
in two different threads "simultaneously", you will always end up with x
increased by 2, as opposed to x=x+1
with optimization switched off.)
What I wonder is whether variable |= constant
, and the likes are thread-safe or do I have to protect them with a mutex?
(...or is it CPU-dependent? In this case, how is it on ARM?)
You are wrong. There is no guarantee that ++ is atomic and neither is there for the compound assignment operators, or indeed for any C++ operation.
x++
is often implemented in 3 instructions: Read X into a register, Increment it, and Write it back to memory.
Your thread may be pre-empted in between any of those.
For the change in value to be visible across cores, a += (for instance) would have to load the value, add the increment and then store it. This means that the operation will not be atomic.
To ensure atomicity you'd need to put appropriate locking around the operation.
No operator in C or C++ is guaranteed to be atomic. They might be on your platform, but you won't know for sure. Typically, the only operation that is atomic is the an instruction Test and Set, which is usually available on most modern CPUs in some form as the basis for implementing semaphores.
No, they're not atomic! If you need atomic operations on primitive types, and you're using linux, you can take a look here: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html and/or atomic.h...
++ might be atomic on your compiler/platform, but in the c++ specs it is not defined to be atomic.
If you want to make sure to modify a value in an atomic way, you should use the appropiate methods, like Interlocked* on windows.
Same for all the other routines. If you want atomic operations, you should use the appropiate calls, not the standard ones.
It's both compiler and CPU dependent. Some instruction sets provide atomic instructions for these (on machine-sized ints).
However, there's no guarantee that you compiler will use those instructions and won't optimize your code in a non-threadsafe way. You need to either write routine in assembly or use a compiler specific technique (such as instrinsics) that provides atomicity (or use a library that uses one of those techniques).
Specifically on ARM: The ORR/ADD/AND instructions take two operands and place the result in a register. Either operand can be the same register as the result register, so they can used as an atomic |=, +=, &=.
Of course, the result is put in a register and the first operand must also come from a register, so you'll have to make sure the register loads are done atomically.
Not only are they not atomic, like all operations, but they can have very interesting results. For example, if the compiler sees that it writes to x, it is allowed to use x as a temporary variable, rather than using up registers or stack space. This means x may temporarily contain ANY value, not just values that make sense for x
http://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong
A duplicate was directed here, and this needs an update. The “new” C11 language enables an atomic attribute which admits that:
_Atomic int a;
...
a += 3
can be compiled into an (atomic) unbounded loop. Thanks for the gift standards folks, I really wish you hadn’t.
1: in some architectures, atomic operations are only possible on memory which supports certain access protocols. ARMv7, MIPS for example turn the sequence into:
do {
x = LoadLinked(a) + 3;
} while !StoreConditional(x, &a);
but LoadLinked/StoreConditional is undefined for some memory/cache types. Enjoy debugging that.
2: Related is false sharing which is an artifact of LoadLinked, StoreConditional operating upon cache lines (eg. 32, 64, 256 bytes) not sub-blocks. So: _Atomic int a[4]; might require 4* cache line size (thus 1024 bytes) to safely permit simultaneous atomic operations on a[n] and a[n+1], because 4 cpu’s could be fighing to update a[0..3], but never succeeding.
Hopefully the next standard will recognize the inherent failure of attribute decoration, and reinstate c89 as the rightful C standard.
It's worth mentioning that these operators can be overloaded, so there can certainly be no general guarantee that they are atomic for all classes.
Even if ++
is an atomic operation, that does not imply that two threads doing ++x
will result in x
being exactly two higher. You have to synchronize the threads somehow, or otherwise they won't necessarily see each other's changes.
You have to protect your variable, with a mutex for instance
精彩评论