4

Lets say we have a structure as below-

struct test
{
    int a;
    int b;
};

I make a atomic variable of this structure and try to update a and b. Will these operations be atomic? What does it mean to make a structure/class atomic?

std::atomic<test> t;
t.a = 10;   // is this an atomic operation?
t.b = 20;   // is this an atomic operation?
// I understand a and b are not atomic in themselves but I am confused     
// as to when you say struct temp is atomic what does it mean?
// does it mean the t instance's this pointer is atomic?
user888270
  • 613
  • 2
  • 8
  • 16
  • Possible duplicate of [How to use std::atomic<> effectively for non-primitive types?](https://stackoverflow.com/questions/13885617/how-to-use-stdatomic-effectively-for-non-primitive-types) – underscore_d Jul 19 '17 at 13:27
  • short answer: no, as the documentation explains, it makes getting and setting copies of the entire struct atomic, but not direct access to its members. – underscore_d Jul 19 '17 at 13:28
  • Pointless because `t.a` is invalid. `a` is a member of `test`, not `atomic` – LWimsey Jul 19 '17 at 13:34
  • 1
    @LWimsey (I still dream of `operator.`) – underscore_d Jul 19 '17 at 13:43

1 Answers1

5

Your are wrapping a POD in an atomic type. On the atomic object t, only atomic operations can be performed, such as load(), store() and compare_exchange_weak(). Those operations apply to the entire POD (not a part of it) and are indivisible; i.e. they happen uninterrupted, or they don't happen at all.

If you want to atomically change member a, that is only possible while updating the entire t object, but since you don't want to modify member b, you'll need a CAS (compare-and-swap) operation:

std::atomic<test> t;

test expected = t.load();
test desired;

do {
    desired = expected;
    desired.a = 10;

} while(!t.compare_exchange_weak(expected, desired));

If t is modified by another thread of execution between load() and compare_exchange_weak(), the latter will update expected (an lvalue) with the new value of t and return 0. You then set desired again based on the updated expected and try again.

With a plain store() instead of a CAS, an update made by another thread could be overwritten (i.e. lost).

LWimsey
  • 6,189
  • 2
  • 25
  • 53