3

Is it correct to use std::memory_order_relaxed at the following code?

#include <atomic>
#include <array>
#include <iostream>
#include <thread>

using namespace std;

int main() {
    std::atomic<int> counter(0);

    constexpr size_t thread_count = 10;
    std::array<std::thread, thread_count> threads;
    for (auto& th : threads) {
        th = std::thread([&counter]() {
            for (int j = 0; j < 100; ++j) {
/*1*/           counter.fetch_add(1, std::memory_order_relaxed);
            }
        });
    }

    for (auto& th : threads) th.join();

/*2*/ std::cout << counter.load(std::memory_order_relaxed) << std::endl;

    return 0;
}

I have a method call counter. It doesn't matter when the counter will be actually incremented (/*1*/), it's enough if it will be incremented some time. But when I call atomic::load (/*2*/), all counter changes that have been made should be visible.

Is it correct to use std::memory_order_relaxed in lines /*1*/ and /*2*/?

1 Answer 1

5

Yes, that's fine. The thread joining provides the necessary synchronization point that ensures that the final load() sees the correct value.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! If I replaces th.join() by std::this_thread::sleep_for(some long period of time), will be this code still correct? Or I should use at least counter.load(std::memory_order_acquire)?
@york.beta: No. You must have a synchronization point, e.g. a release/acquire pair. (The program wouldn't be incorrect as such, since you're only accessing an atomic variable, but the result would be unpredictable.) Then again, without joining, the state of the counter would be unpredictable anyway.
I had the same question and the same comment to the answer. Thanks @Kerrek SB ! Here is another one: Would a counter.fetch_add(0, std::memory_order_relaxed); to read counter achieve the same as having synchronization points through the join()s?
The rationale is here: stackoverflow.com/a/8833218/643011 "The only way to guarantee you have the "latest" value is to use a read-modify-write operation such as exchange(), compare_exchange_strong() or fetch_add()" But then again the whole question would be pointless because however likely it is not guaranteed in which order the threads are scheduled and the writers are really finished. Even if it's a really long sleep.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.