This page talks about a CAS loop in details: https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
An example of fetch_multiply
in C++:
uint32_t fetch_multiply(std::atomic<uint32_t>& shared, uint32_t multiplier){
uint32_t oldValue = shared.load();
while (!shared.compare_exchange_weak(oldValue, oldValue * multiplier)){}
return oldValue;
}
Essentially if the *memory
value matches our oldValue then a newValue
gets stored atomically, else oldValue get updated with *memory
.
I have 2 questions:
1 - Why do we have to check if oldValue
is still unchanged in memory? What happens if we just write newValue to memory? Are we trying to avoid overwriting or using an intermediate value from another thread?
2- Suppose this scenario with 2 threads:
- Thread B is trying to store a non-aligned value non-atomically. Store tearing occurs.
- Thread A attempts a swap.
- Swap fails as oldValue doesn't match. An intermediate (teared) value from memory gets loaded to our oldValue.
- Thread A does multiplication with an intermediate value and attempts another swap which succeeds.
- Now Thread B writes the remaining of its values to the same location partially overwriting our previous write.
I'm assuming Thread B
could operate with that much delay and if so not only we
multiplied with an intermediate value, it even got partially overwritten afterwords and CAS did nothing.