问题
I am trying to perform an addition on a double atomically in a loop using a compare and exchange scheme with this function:
namespace my
{
template<typename value_type>
value_type atomic_add(std::atomic<value_type>& operand, value_type value_to_add)
{
value_type old = operand.load(std::memory_order_consume);
value_type desired = old + value_to_add;
while (!operand.compare_exchange_weak(old, desired, std::memory_order_release, std::memory_order_consume))
desired = old + value_to_add;
return desired;
}
}
This is used in my code like so:
[ size of containers = 62, scalar = 318.0, values in containers between 0.0 and 55.0, all values are of type double ]
for(size_t i = 0; i < container.size(); i++)
{
my::atomic_add<double>(Q, container2[i] - std::pow(container3[i], 2) / scalar);
}
The output is 0.57784502195324539
.
However, replacing all my_atomic with the +=
operator, and replace all std::atomic<double>
with double
gives 0.52something
, which is closer to what I was expecting.
Any idea why this is happening?
Thank you.
回答1:
I seem to have fixed this issue so I am going to post an answer as a cautionary tale for other developers.
Here is a minimal working example:
#include <iostream>
#include <atomic>
#include <vector>
namespace my
{
template<typename value_type>
value_type atomic_add(std::atomic<value_type>& operand, value_type value_to_add)
{
value_type old = operand.load(std::memory_order_consume);
value_type desired = old + value_to_add;
while (!operand.compare_exchange_weak(old, desired, std::memory_order_release, std::memory_order_consume))
desired = old + value_to_add;
return desired;
}
}
int main()
{
std::vector<double> vector;
for(int i = 0; i < 100; i++)
{
double a;
a = 2.0;
vector.push_back(a);
}
std::atomic<double> d;
for(int i = 0; i < vector.size(); i++)
my::atomic_add(d, vector[i]);
std::cout << d << std::endl;
}
The output of which is 202
. It appears that d
is initialized to 2.0
. The moral of this story is to always make sure that your std::atomic
s are initialized to a sane value.
Furthermore, other answers have pointed out that it is generally a bad idea to store std::atomics
s in a vector as they are not CopyAssignable
and CopyConstructible
.
来源:https://stackoverflow.com/questions/40882023/addition-on-stdatomicdouble-not-adding-up-to-non-atomic-counterpart