??
You say that it is only thing outside of the execution model that require volatile, but you explain that a signal handler requires volatile and to be the signal-atomic type. ;) In practice, volatile with lock-free types (that now stdatomic has a way to query whether types are lock-free) are correctly used all the time to pass data between threads.
A volatile declaration may be used to describe an object corresponding to a... an object accessed by an asynchronously interrupting function.
Like, execution in other thread contexts.
Or, from the C99 Rationale:
The translator may assume, for an unqualified lvalue, that it may read or write the referenced
object, that the value of this object cannot be changed except by explicitly programmed actions
in the current thread of control, but that other lvalue expressions could reference the same
object.
vs volatile:
No cacheing through this lvalue: each operation in the abstract semantics must
be performed (that is, no cacheing assumptions may be made, since the location
is not guaranteed to contain any previous value). In the absence of this qualifier,
the contents of the designated location may be assumed to be unchanged except
for possible aliasing.
> Double-checked locking is problematic in large part because of hardware reordering of loads and stores.
This was unsafe even on in-order uniprocessors, because the compiler was free to reorder loads and non-aliased stores.