|
|
|
|
|
by JonChesterfield
766 days ago
|
|
If you do the loads as uint32, you lose the single atomic operations on two different values which was the whole point of this exercise. Using a single uint64 as the memory type works, but you no longer have two different names fields and have to pack/unpack them by hand. There's no ub if you use the compiler extension, just totally clear code that does the right thing |
|
There's no need for any flirting with undefined behaviour through type-punning.
When doing the atomic write, you prepare the uint64_t value to write by using bitwise operations, and then perform the atomic write of the resultant uint64_t value.
When doing the atomic read, you atomically read the uint64_t value, then use bitwise operations to unpack the original pair of uint32_t values.
Put differently, writing is done by pack-then-atomically-write, and reading is done by atomically-read-then-unpack.
Turns out we're both overthinking it though, there's a more direct way: use a struct containing an array of 2 uint32_t elements, or declare a struct with 2 uint32_t members. Both C and C++ support atomic reads and writes of user-defined types. For a C++ example showing this see [0]. This will be atomic and, presumably, should be lock-free where possible (hard to imagine the compiler would introduce padding in the struct type that would sabotage this).
> Using a single uint64 as the memory type works, but you no longer have two different names fields and have to pack/unpack them by hand.
Yes, the stored variable would hold 2 different meaningful values, which is a little ugly.
> There's no ub if you use the compiler extension, just totally clear code that does the right thing
Anyone with a deep knowledge of the language will quickly recognise it as incorrect per the language standard. I wouldn't call that totally clear code that does the right thing.
Your proposed solution is only assured to behave as expected if the correct compiler-specific flags are used, otherwise it will introduce undefined behaviour. There's no guarantee that a compiler will even offer such a flag. It's also likely to trigger compiler warnings.
[0] https://en.cppreference.com/w/cpp/atomic/atomic