grundprinzip
grundprinzip

Reputation: 2491

C++11 std::atomic_fetch_add vs __sync_fetch_and_add

I'm currently having troubles correctly understanding the usage of the new std::atomic types. For my case I have the following assumptions:

  1. I have a contiguous memory location of uint64_t values stored in memory
  2. I have two kinds of accesses simple increments and atomic increments

Originally I implemented the methods like this

uint64_t inc(const size_t pos) { return _data[pos]++; }
uint64_t atomic_inc(const size_t pos) { return __sync_fetch_and_add(&_data[pos], 1); }

Now I wanted to port this correctly to C++11 and was wondering how should I handle this correctly. From my understanding of std::atomic_fetch_add one basically needs an atomic integral value to do this. However, how do I need to implement this correctly, so that I can point using an atomic variable to a location and increment the value?

Thanks!

Upvotes: 4

Views: 9766

Answers (2)

Anthony Williams
Anthony Williams

Reputation: 68631

You cannot use C++11 facilities to get atomic access to a variable that is not declared as an atomic type. You would need to replace your array of uint64_t with an array of std::atomic<uint64_t>. On many platforms, this will have the same size and alignment as plain uint64_t, but all operations will be atomic.

You can then use data[pos].fetch_add(1,memory_order) to do the atomic increment with the specified memory_order. If you need a memory order of std::memory_order_seq_cst (which is probably the closest to the GCC __sync_fetch_and_add), then the memory order can be omitted, or you could use an increment operator, e.g. data[pos]++.

Upvotes: 9

JoergB
JoergB

Reputation: 4463

You can't.

A C++11 atomic object encapsulates its base type. It does not provide access to its value as lvalue nor can you set it up to provide atomic operations on a preexisting object of the underlying type (at a given memory location).

Depending on the platform any given atomic type might have special requirements (e.g. stronger alignment constraints) or need auxiliary data (most atomic types are not guaranteed to be lock-free)

Doing what you want to do still requires platform-specific functionality.

If you want to do non-atomic increments,the closest you can get is:

  atomic<uint64_t> data(initial_value);
  data.store(data.load(memory_order_relaxed) + 1, memory_order_relaxed);

This will still do atomic loads and stores, but no memory fencing or atomic read-modify-write operations.

Upvotes: 3

Related Questions