dragon-curve dragon-curve - 29 days ago 8
C++ Question

How can I properly increase C++11 std::atomic?

I'm new to multi-thread programming, and I found the std::atomic in C++11.

So, I tried to figure it out how much time takes atomic operations are.

I tried this code:

using namespace std;
using namespace std::chrono;

constexpr int NUM_THREADS = 8;
constexpr int LIMIT = 100000;

atomic<int> sum = 0;

void foo(int idx) {
while (true) {
if (sum.load() >= LIMIT) {
return;
}
sum.fetch_add(1);
}
}


with main:

int main(void) {
thread threads[NUM_THREADS];

auto start = high_resolution_clock::now();

for (int i = 0; i < NUM_THREADS; i++) {
threads[i] = thread(&foo, i);
}

for (int i = 0; i < NUM_THREADS; i++) {
threads[i].join();
}
auto du = high_resolution_clock::now() - start;

cout << "computing time\t\t" << duration_cast<milliseconds>(du).count() << "ms" << endl;
cout << "number of thread\t" << NUM_THREADS << endl;
cout << "sum\t\t\t" << sum << endl;

return 0;
}


But 'sum' is not always same as 'LIMIT'.

To my knowledge, the atomic operations thread-safe when 'called'. So, yes, I think my code is wrong, but I couldn't find out how to make this work out properly.

How can I get correct result with that main?

(well, this version will make 'sum' and 'LIMIT' equal, but I think this isn't a good way...)

void foo(int idx) {
for (int i = 0; i < LIMIT / NUM_THREADS; i++) {
sum.fetch_add(1);
}
}

Answer

As it was said in the comments your problem is that the variable is changed by another thread between the time you load it and the time you increment it.

You could change your loop e.g. like this to fix it:

while (true) {
    auto current = sum.load();        
    if (current >= LIMIT) {
        return;
    }
    auto next = current + 1;
    sum.compare_exchange_strong(current, next));
}
Comments