5

I have a struct, let's call it struct foo, to which I'd like to add an atomic_flag variable. So far, I've been callocing the struct given that it mostly needs to be zero initialized. How should I be initializing the atomic_flag member?

struct foo{
    //...
    atomic_flag a_flg;
    //...
};
struct foo *foop = calloc(1,sizeof *foop);
if(!foop) return -1;

//should I be giving up `calloc` (/`malloc`+`memset`) in favor of `malloc`+this?
*foop = (struct foo){ ATOMIC_FLAG_INIT };

Edit:

I have found this related DR#421 by Jens Gustedt that proposes that zero/default-initialization be made to just work for atomic_flags. How can I find out if it's been accepted?

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 1
    Note that for the `*foop = ...` initialization, you still need to make `foop` point somewhere valid, and that you need to explicitly specify initialization for *all* members of the structure. – Some programmer dude Apr 02 '19 at 13:42

1 Answers1

5

The C11 Standard says on 7.17.8p4:

An atomic_flag that is not explicitly initialized with ATOMIC_FLAG_INIT is initially in an indeterminate state.

And there is no indication of what the atomic_flag type is or its contents, so zero'ing does not help here.

You will need to initialize it to a known state either using the macro or the atomic_flag_clear or atomic_flag_clear_explicit functions.

Acorn
  • 24,970
  • 5
  • 40
  • 69
  • 2
    Thanks. I'm also reading it that way, but it seems very awkward to me. I have found this [DR#421](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2148.htm#dr_421) by Jens Gustedt that recommends that zero initialization should just work for atomic flags, but it doesn't look like it's been approved (or has it?). – Petr Skocik Apr 02 '19 at 13:51
  • 2
    @PSkocik: in practice on probably any real implementation (and definitely all mainstream x86 and ARM compilers like gcc/clang/MSVC/ICC), it *does* work. `atomic_flag` is required to be lock-free, and on normal implementations it's effectively just a 1-byte `bool`. It's safe for that to be zero-initialized. Of course this is on CPUs that support lockfree atomic ops on other types up to at least register width. (Check the asm to see how it uses it if you're ever not sure that all-zeros is a valid object representation for `atomic_flag`.) – Peter Cordes Apr 02 '19 at 14:47
  • 2
    @PSkocik, no, unfortunately it has not been approved, only the one for `ATOMIC_VAR_INIT` has been. When we discussed that at that time I learned that some platforms seem to need to use a different value for initialization, depending on the atomic primitives they have. And initializing `malloc`ed data with a compound literal is a good habit, so I would suggest that you keep it like this. – Jens Gustedt Apr 02 '19 at 15:13
  • @JensGustedt Thank you! – Petr Skocik Apr 02 '19 at 15:39
  • Looks like `atomic_flag_clear_explicit(&foop->a_flg,memory_order_relaxed)` should be the optimal way to do it. – Petr Skocik Apr 02 '19 at 15:46
  • @JensGustedt: What fraction of C code will ever be called upon to run on platforms which couldn't allow "normal" initialization at no extra cost? What disadvantage would there be to having standard macros that would indicate things like whether normal initialization would work with atomic types, whether pointers in all-bits-zero (e.g. received from `calloc`) will be initially null, whether integer operations other than divide/remainder are always free of side-effects, etc.? – supercat Apr 05 '19 at 17:57
  • @supercat, why are you asking me this? This was certainly not my decision to keep it that way. – Jens Gustedt Apr 06 '19 at 12:38
  • @JensGustedt: I was wondering if you have any insight to the mentality of some Committee members that seems to oppose any effort to define the behavior of code that exploits common platform features, when running on platforms that support such features. – supercat Apr 07 '19 at 00:43
  • @supercat, there are at least three answers to this. (1) Going to the committee meetings I learned a lot about how I live in a quite restricted bubble, many C platforms with their own constraints exist that I was not aware of. (2) This is undefined in the good sense of the term, so implementations or other standards (such as POSIX) may do whatever they want with this. (3) The C committee and their perception of things evolve over time, so today it might even be possible to change that particular aspect. – Jens Gustedt Apr 07 '19 at 07:14
  • @JensGustedt: C could be made more useful on *both* common and uncommon platforms if it made features which can be easily supported on some platforms and expensive on others optional, but required that implementations predefine macros or intrinsics so programs could refuse compilation on implementations that don't support them. The choice of what features to support would be a QoI issue for implementations, and the choice of what features to require could be a QoI issue for programs, but a program that tests for all the features and guarantees it needs... – supercat Apr 07 '19 at 16:14
  • ...and might fail on some implementations but wouldn't invoke UB on any of them. Saying, for example, that implementations may use *any* format for storing signed or unsigned integers, and need not use power-of-two modulus for unsigned types, but that implementations must define macros indicating their integer semantics, would make implementation practical on the 36-bit Univac which couldn't support C99, but provide all the advantages one would get from mandating two's-complement integers. – supercat Apr 07 '19 at 16:20