What is the behavior of x86 for something like this?
template <typename Integer>
void write(Integer&);
auto integer = std::uint64_t{0};
auto atomic = reinterpret_cast<std::atomic<std::uint32_t>*>(&integer);
auto one = std::thread{[&]() {
write(integer);
}};
auto two = std::thread{[&]() {
read(atomic.load());
}};
A 32 bit atomic load in x86 gets compiled to this (somehow the generated assembly does not include the lock prefix)
mov edi, DWORD PTR [rdi]
(Assume little-endianness, which puts the atomic integer at the right place to observe the least significant 32 bits of the 64 bit integer)
Two related questions -
- What does x86 describe as the behavior of such a scenario?
- What would the
write()function need to do in this case to break the above code? The width of the read/write inwrite()can be anything, not necessarily confined to 64 bits, assuming however, that there is enough padding to make it take up 64 bits.write()can also execute an atomic operation.
Context: The place I work at has code that does this, and nothing seems to be breaking at the moment, I am pretty confident that this is bad code and can break in some situation. However, I do not know much about x86 and hardware in general. I would like to get to the bottom of this behavior, figure out if this is a problem and potentially fix the problem. A strong reference from x86 (ARM would do too) would be great.