5

As shown below, I have a struct that has a few bitfields. I also have a union that contains a volatile 64-bit value and this struct. Are changes to the struct, accessed through the union, also volatile?

i.e. since the struct and the volatile int share the same memory location, do accesses to the struct also result in accessing memory for each access, or will the compiler store them in registers?

typedef struct {
  uint64 my_info_1:12;
  uint64 my_info_2:16;
  uint64 reserved: 36;
  } my_info_s;

typedef union {
  my_info_s my_info_struct;
  volatile unsigned long long my_info_vol; //64 bit
} my_info_u;

my_info_u my_info;
//Are these volatile accesses?
my_info.my_info_1 = 4;
my_info.my_info_2 = 8;

//This is the motivation- update a bunch of bitfields, but set them in one shot.
atomic_set(atomic_location, my_info.my_info_vol);

I cannot use locks/mutexes to achieve this because of some real-time constraints.

hat
  • 781
  • 2
  • 14
  • 25
nirvanaswap
  • 859
  • 2
  • 11
  • 21
  • https://stackoverflow.com/questions/4306186/structure-padding-and-packing You need to consider of padding.Ensure that sizeof(my_info_s) is 64. – Tsakiroglou Fotis Mar 15 '18 at 18:55
  • 1
    It would not have occurred to me that it was even legal to put storage classes on individual members of structs or unions, but I guess it's syntactically valid since there aren't two separate grammars for declarations in or outside of structures. I don't think it's meaningful, but now that you ask, I don't know of a rule against it. (gcc, at least the version I tried, seems to accept them without complaint.) – Steve Summit Mar 15 '18 at 18:56
  • 1
    What would a volatile bitfield mean? You cannot really read or write 12 or 36 bits without affecting other bits of the struct. So looks like No. – Bo Persson Mar 15 '18 at 19:36
  • 2
    Consider that the address of the struct could be taken and passed to a routine in another module that knows nothing about the union. This routine will merely see a definition of a `struct` type that is not volatile, and the compiler would not treat it as volatile while compiling this routine. Therefore, accesses to a struct that shares a union with a volatile object cannot be relied upon to be volatile. – Eric Postpischil Mar 15 '18 at 20:05
  • 1
    Given your "I cannot use locks/mutexes to achieve this ...", I hope you're not trying to use `volatile` to make your code thread-safe, because that won't work. See [Volatile: Almost Useless for Multi-Threaded Programming](https://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming) and [Should volatile Acquire Atomicity and Thread Visibility Semantics?](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html) Note that second author is none other than Hans Boehm. – Andrew Henle Mar 16 '18 at 13:36

2 Answers2

2

I don't know what the official standard says, but let's think about this logically:

Unions

The volatile 64-bit type is just one option for the union. If "everybody agrees" to interpret the union as the non-volatile type, then its as though that option doesn't exist - except in terms of size. So I would say your union is not inherently volatile.

However, I would advise you: Don't ever put volatile and non-volatile members in the same union. Doing so is just asking for trouble, confusion and bugs.

Structs

If a member is volatile, i.e. if its contents can be modified between reads by the current execution thread, this is true by definition for any structure that contains it - its contents (albeit perhaps just some of it) can also be thus modified. So structs with a volatile member are themselves volatile.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
2

Well, as I can see, your original question can be rephrased to "Does volatile being an equivalent of thread-safety". And sad answer is "no".

For multi-threading code, there are two main enemies:

  1. Compiler-level optimization. This one could be defeated with "volatile" classifier. (yes, it surely be just broken compiler that optimizes volatile variable as a register - then, change your compiler with correct one like GCC or CLang)
  2. CPU-level optimization. Yes, while moving your code through the internal conveyor(s), CPU can do some tricks and gotchas to speedup overall process. And without special precautions your code may be executed with very different order of steps if CPU thinks that total result of the execution would not be changed by given optimization. Sadly, "volatile" is not much help to advise CPU what can be done and, more importantly, what must not be done during that conveyor optimizations.

All after all, as soon as you can't use locks and mutexes, it seems you're looking for so called "lock-free programming". Take a look at Lock-Free Data Structures by Andrei Alexandrescu or this Introduction to Lock-Free Programming

Yury Schkatula
  • 5,291
  • 2
  • 18
  • 42