0

Expanding from this question (How to do an atomic increment and fetch in C?)

In C, using Clang compiler, how can I do the atomic equivalent of

const int v = ++x

As I understand it, v = atomic_fetch_add(&x, 1) will return the original value (ie v = x++), which is a post-increment.

How do I return the updated value of x instead?

Note: this question is about C, and any replies with "use std::atomic<>" will be downvoted accordingly.

Justicle
  • 14,761
  • 17
  • 70
  • 94

3 Answers3

6

You can use

v = atomic_fetch_add(&x, 1) + 1;
ikegami
  • 367,544
  • 15
  • 269
  • 518
3

You can use the clang/gcc intrinsic function __atomic_add_fetch(), which first adds to a number then returns the new value (There's also __atomic_fetch_add() which acts like the C11 atomic_fetch_add()):

int x = 1;
const int v = __atomic_add_fetch(&x, 1, __ATOMIC_SEQ_CST); // v is 2
Shawn
  • 47,241
  • 3
  • 26
  • 60
2

For _Atomic int x;, your example local = ++shared; already does work atomically, like GNU C __atomic_add_fetch (not ..._fetch_add). ISO C11 is no different for this than ISO C++.

The downside is that you can't specify a memory-order weaker than seq_cst, and there's no equivalent for other operators, unlike GNU C __atomic_or_fetch.

Compilers are generally decent at optimising ISO C atomic_fetch_add(&x, 1) + 1, although it wasn't until GCC12 that GCC managed to make the same asm for this as for using the return value of ++x. Before that, on LL/SC machines (like ARM, and AArch64 before ARMv8.1), it would do fetch_add but then not using the incremented value it had in a register, doing a separate add after the loop on the load result. (Godbolt)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Avoiding `tmp = ++shared` makes sense if you want to use a memory order weaker than `seq_cst`, though. Then you need to use `atomic_fetch_add_explicit(...) + 1`, or GNU C `__atomic_add_fetch`. – Peter Cordes Jun 16 '22 at 23:38