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.