Reputation: 5651
I've got a structure that contains an atomic field:
#include <stdatomic.h>
struct s {
...
atomic_int a;
};
This structure is allocated with calloc
:
struct s *p = calloc(1, sizeof(struct s));
Is it portable to expect p->a
to be initialised to 0? There are enough barriers in the code so that weakly consistent initialisation is fine, but is the initial value guaranteed to be 0?
Upvotes: 10
Views: 751
Reputation: 78923
No, this is not portable in general. calloc
only guarantees a byte-wise 0
value of the underlying object. For types that (may) have a state this is not equivalent to an initialization. You definitively have to use atomic_init
to put your object into a valid state.
The reason for this are platforms that hold a "lock" in addition to the base object because they don't implement the corresponding assembler instruction. So to be portable you really need to use ATOMIC_VAR_INIT
or atomic_init
for all atomic objects that are not statically allocated.
That said, I don't know of any existing platform that would need such cruft for atomic_int
. If your platform has ATOMIC_INT_LOCK_FREE
set to 2
and sizeof(atomic_int)==sizeof(int)
, you can be relatively sure that your strategy works. You could test that in a _Static_assert
.
Upvotes: 3
Reputation: 153517
struct s *p = calloc(1, sizeof(struct s));
struct s *q = p;
// some other thread
foo(*q);
The initialization to zero is accounted for before p
or any of its assginees can access the memory. It is 0
.
Also see deferred zero-ing.
Upvotes: -1
Reputation: 4386
My guess is that this is not portable/safe.
It's very likely that calloc()
end up doing a simple memset()
on the memory area. This simple memset()
would not issue the required memory barriers to ensure that other threads reading the structure would see the p->a
as 0
.
Upvotes: 0