Rajeev Mehta
Rajeev Mehta

Reputation: 659

Modify and read from an atomic variable

A class has the following member,

std::atomic<int> clientId{0};

And given the following inside it's member function,

int currentId = ++clientId.load();

Is there a race condition here? I am trying to do something similar to generate clientId's. Multiple threads could execute this part of the code. Can a thread that has incremented clientId and before it tries to load() and get a copy, another thread increment the same and thus end up with a race condition? If yes, is protecting with a mutex the best way using an ordinary int and getting a copy inside the mutex?

Please explain.

Upvotes: 1

Views: 687

Answers (1)

Holt
Holt

Reputation: 37606

std::atomic<int>::load() does not return a reference, so you are not incrementing the current value of clientId, you are incrementing the temporary returned by load().

You need to do:

int currentId = ++clientId; // no .load()

There are overloaded operators for std::atomic. The memory order for the pre-increment operator is std:: memory_order_seq_cst1, which says:

A load operation with this memory order performs an acquire operation, a store performs a release operation, and read-modify-write performs both an acquire operation and a release operation, plus a single total order exists in which all threads observe all modifications in the same order (see Sequentially-consistent ordering below)

So you are safe from data-race condition here.

1 The standard says that ++clientId is equivalent to fetch_add(1) + 1, and the default memory order for fetch_add is std::memory_order_seq_cst.

Upvotes: 4

Related Questions