Search code examples
atomicc11

What does assignment mean to a C11 atomic?


For example,

atomic_int test(void)
{
  atomic_int tmp = ATOMIC_VAR_INIT(14);
  tmp = 47;                    // Looks like atomic_store
  atomic_int mc;               // Probably just uninitialised data
  memcpy(&mc,&tmp,sizeof(mc)); // Probably equivalent to a copy
  tmp = mc + 4;                // Arithmetic
  return tmp;                  // A copy - perhaps load then store
}

Clang is happy with all this. I've read section 7.17 of the standard, and it says a lot about the memory model and the defined functions (init, store, load etc) but doesn't say anything about the usual operations (+, = etc).

Also of interest is the behaviour of passing struct wot { atomic_int value; } to functions.

I would like to believe that assignment behaves identically to an atomic load then store using memory_order_seq_cst.

Even more optimistically, I would like to believe that struct assignment, passing to function, returning from function and even memcpy also behaves identically to carefully copying the bit pattern across under memory_order_seq_cst.

I can't find any supporting evidence for either belief in the standard though. There's definitely a chance that assignment and memcpy of atomic primitives is undefined behaviour.

How should primitive operations on atomic primitives behave?

Thanks!


Solution

  • Operations on objects that are _Atomic qualified (and atomic_int is just a different writing for that) are guaranteed to have sequential consistency. You find that mentionned at the end of the semantics section for each of the operands. (And maybe the mention for assignment is missing.)

    Your code is not correct because memcpy is undefined here (the sizes might not agree), although it probably will work on most of the architectures.

    Also the line

    tmp = mc + 4;                // Arithmetic
    

    doesn't do what your comment claims. This is not arithmetic on an atomic object, but a load followed by an ordinary addition. More interesting would be

    mc += 4;                // Arithmetic
    

    which is an atomic operation with sequential consistency. From section 6.5.16.2 of the C11 standard:

    A compound assignment of the form E1 op = E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation. If E1 has an atomic type, compound assignment is a read-modify-write operation with memory_order_seq_cst memory order semantics.

    NOTE: Since C17 the ATOMIC_VAR_INIT macro is considered obsolete, and it has / will be removed in C23