1

For example, with multiple threads executing the update() function:

// Statically allocated
atomic<int> high_water{0};
//...
void update(int meas)
{
int i;
bool replaced;
do
{
i = high_water.load(?);
if (i >= meas)
  break;
replaced = high_water.compare_exchange_strong(i, meas, ?, ?);
}
while (!replaced);
// ...

(I am trying to implement a shared high water mark of individual measurements taken in multiple threads.)

2 Answers 2

2

compare_exchange_strong is atomic with respect to high_water, no matter what memory order you specify to it. Memory ordering only matters with respect to other memory operations. It largely depends on how and when other threads need to see high_water. Since meas is only visible in this thread, so there are no other loads and stores to consider. Thus, memory_order_relaxed is correct.


As a secondary note, compare_exchange_strong replaces the first parameter with the observed value, so performing that load is redundant.

int i = high_water.load(std::memory_order_relaxed);
while (i < meas
      && high_water.compare_exchange_strong(i,
                                            meas,
                                            std::memory_order_relaxed,
                                            std::memory_order_relaxed
                                           )
      )
    continue;
Sign up to request clarification or add additional context in comments.

1 Comment

while ( i < meas && ! high_water.compare_exchange_strong(…) ) ;
2

what memory order(s) should I use for a load followed by a compare exchange?

It is impossible to tell because you don't show the code where update() is called. Reordering of memory operations surrounding that call is a real thing on certain platforms if you use memory_order_relaxed (or anything weaker than the default for that matter). high_water may actually be used to synchronize data between threads. If you are not worried about those possible reorderings, then std::memory_order_relaxed is fine.

Generally, for these kinds of operations, I would not use a weaker ordering than the default (std::memory_order_seq_cst). Since std::compare_exchange_strong is a Read-Modify-Write (RMW) operation, which by definition is expensive because it synchronizes the value of the atomic between cores, changing memory ordering is not going to be much of an advantage. At least on X86, with your code, the compiiler will emit the exact same object code for std::memory_order_seq_cst and std::memory_order_relaxed.

Side note, since you are in a loop, you may want to use compare_exchange_weak(), which may fail spuriously, but that is handled by the loop.

Comments

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.