2

I have a shared variable s and private variable p inside parallel region.

How can I do the following atomically (or at least better than with critical section):

if ( p > s )
    s = p;
else
    p = s;

I.e., I need to update the global maximum (if local maximum is better) or read it, if it was updated by another thread.

user2052436
  • 4,321
  • 1
  • 25
  • 46

1 Answers1

3

OpenMP 5.1 introduced the compare clause which allows compare-and-swap (CAS) operations such as

#pragma omp atomic compare
if (s < p) s = p;

In combination with a capture clause, you should be able to achieve what you want:

int s_cap;

// here we capture the shared variable and also update it if p is larger
#pragma omp atomic compare capture
{
   s_cap = s;
   if (s < p) s = p;
}

// update p if the captured shared value is larger
if (s_cap > p) p = s_cap;

The only problem? The 5.1 spec is very new and, as of today (2020-11-27), none of the widespread compilers, i.e., those available on Godbolt, supports OpenMP 5.1. See here for a more or less up-to-date list. Adding compare is still listed as an unclaimed task on Clang's OpenMP page. GCC is still working on full OpenMP 5.0 support and the trunk build on Godbolt doesn't recognise compare. Intel's oneAPI compiler may or may not support it - it's not available on Godbolt and I can't get it to compile OpenMP code.

Your best bet for now is to use atomic capture combined with a compiler-specific CAS atomic, possibly in a loop.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186
  • But, even like this you still have a race condition, if you have a thread updating 's' within the "pragma omp atomic compare capture" and another already doing if (s_cap > p) – dreamcrash Nov 27 '20 at 09:15
  • `s_cap` captures the value of `s` at the time the atomic construct runs. If `p` was larger, `s` is updated inside the atomic and `(s_cap > p)` after it is false, so `p` remains unchanged. If `p` was lower, `s` is not updated but `p` is updated to the value of `s_cap`, i.e., the value `s` had during the execution of the atomic. The end result is the same as executing `if (p > s) s = p; else p = s;` in a critical section. – Hristo Iliev Nov 27 '20 at 14:17
  • Yep, thanks, now I get it. I still have a hard time imagining where having something like this code actually makes sense (the OP example). Unless within a ordered constructor. – dreamcrash Nov 27 '20 at 14:22
  • @dreamcash I have multiple threads searching for global max iteratively. Each new global max reduces search space for each thread. So if "this" thread found new max, I want to tell it to other threads. If global max was updated by another thread, "this" thread wants to get new global max to narrow "this" thread's search space – user2052436 Nov 27 '20 at 23:15
  • If you're after the max reduction, at least time the code using a reduction clause. You can also use a reduction clause if you're really after the location of the max. Its hard to see how knowing a running value helps to reduce the computation in other threads... Show us some real code! – Jim Cownie Nov 30 '20 at 08:50