I ran following code many times but why the result for prefix increment , fetch_add() shows the correct result while with add operation (+), it prints the wrong result?
#include <iostream> #include <mutex> #include <future> using namespace std; atomic <int> cnt (0); void fun() { for(int i =0; i <10000000 ; ++i) { //++cnt; // print the correct result 20000000 //cnt = cnt+1; // print wrong result, arbitrary numbers cnt.fetch_add(1); // print the correct result 20000000 } } int main() { auto fut1 = async(std::launch::async, fun); auto fut2 = async(std::launch::async, fun); fut1.get(); fut2.get(); cout << "value of cnt: "<<cnt <<endl; }
atomic::fetch_add (C++11)Atomically adds a value to an existing value that is stored in an atomic object. Memory is affected according to the value of order .
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.
Atomic operations are sequences of instructions that guarantee atomic accesses and updates of shared single word variables. This means that atomic operations cannot protect accesses to complex data structures in the way that locks can, but they provide a very efficient way of serializing access to a single word.
(C++11) [edit] The atomic library provides components for fine-grained atomic operations allowing for lockless concurrent programming. Each atomic operation is indivisible with regards to any other atomic operation that involves the same object. Atomic objects are free of data races.
++cnt
and cnt.fetch_add(1)
are truly atomic operations. One thread is blocked while the other thread reads, increments, and updates the value. As such, the two threads cannot step on each other's toes. Access to cnt
is fully serialized, and the final result is as you would expect.
cnt = cnt+1;
is not fully atomic. It involves three separate operations, only two of which are atomic, but one is not. By the time a thread has atomically read the current value of cnt
and made a copy of it locally, the other thread is no longer blocked and can freely modify cnt
at will while that copy is being incremented. Then, the assignment of the incremented copy back to cnt
is done atomically, but will be assigning a stale value if cnt
has already been modified by the other thread. So the final result is random and not what you would expect.
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