0

How is std::atomic<> compare_exchange() related and translated to/from MS InterlockedCompareExchange64 on a non-atomic value? Are there performance or semantics differences?

For example, are these codes equivalent?

edit : David Haim pointed out that it should have been int64_t atomic_inc_ms(volatile int64_t& val, int64_t less_than)

int64_t atomic_inc_ms(int64_t& val, int64_t less_than) {
 int64_t new_val;
 int64_t old_val = val; 
 while(true)
 {
   if (old_val > less_than) return old_val;
   new_val = old_val + 1;
   int64_t got_val = InterlockedCompareExchange64(&val,new_val,old_val);
   if(got_val == old_val) break;
   old_val = got;
 }

 return new_val;
}

and

int64_t atomic_inc(std::atomic<int64_t>& val, int64_t less_than) {
 int64_t new_val;
 int64_t old_val = val.load();
 do
 {
   if (old_val > less_than) return old_val;
   new_val = old_val + 1;
 } while (!val.compare_exchange_weak(old_val, new_val));

 return new_val;
}

A concern is the line int64_t old_val = val; with no explicit atomic load.

The example is that of Is there atomic increment with the check preconditions, that the atomic value was less than the specified value? and is close to the text book example on how to use compare_exchange_weak.

Are compare_exchange_weak and compare_exchange, semantically equivalent to InterlockedCompareExchangeAcquire64 and InterlockedCompareExchange64 ?

Community
  • 1
  • 1
Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
  • 1
    both will compile to the same thing, aka `lock inc [ptr]`, so no worries. but your code shows why the standard is better, your `val` is not volatile, while `Interlocked*` requires volatile variable. you don't need to think about it when you use `atomic`. plus the protability – David Haim Apr 25 '16 at 19:20
  • @DavidHaim. Thank you! I agree 100%. You beat me to realize this, while I was commenting SergeyA's answer. I had an unclear consern about what the compiler can do with val. – Johan Lundberg Apr 25 '16 at 19:24
  • @DavidHaim, do I understand you right (the edit I made, now `volatile int64_t& val`). – Johan Lundberg Apr 25 '16 at 20:04

2 Answers2

1

Those codes are semantically equivalent. No atomic load for int64_t is of no concern here, since Interlocked* family functions hint X86, where all loads are atomic.

There is a chance that c++ atomics will behave slightly faster than Interlocked* functions, since compiler will generate direct ASM call rather than call a function. However, compiler might recognize Interlocked* function as well.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Ok. Great! And, my code 'int64_t old_val = val;'. There´s no need for volatile or other marker that val can be changed from other thread? Perhaps `volatile int64_t& val`? – Johan Lundberg Apr 25 '16 at 19:21
0

std::atomic is C++ standard. It is portable code that will compile with any compliant compiler

Interlocked* are Windows-specific functions from Windows SDK. Hence that code will not be portable.

Ghostrider
  • 7,545
  • 7
  • 30
  • 44