Inside STL: Waiting for a std::atomic to change, part 1 -- Raymond Chen
When using std::atomic<std::shared_ptr<T>>, the C++ standard defines a "change" as a modification to either the stored pointer or the control block pointer. However, since atomic wait mechanisms typically track only a single memory address, the Microsoft implementation handles this limitation by using a timeout-based polling strategy to detect changes in the control block.
Inside STL: Waiting for a std::atomic<std::shared_ptr<T>> to change, part 1
by Raymond Chen
From the article:
Like other
std::atomic
specializations,std::atomic<
supports thestd::shared_ptr<T>> wait
andnotify_*
methods for waiting for the value to change and reporting that the value has changed. The definition of “changed” in the C++ language specification is that the value has changed if either the stored pointer or the control block pointer has changed. A shared pointer is implemented as a pair of pointers, butWaitOnAddress
can wait on at most 8 bytes, and unix futexes can wait on only four bytes, so how does this work?¹The Microsoft implementation waits for the stored pointer to change, and the
notify_*
methods signal the stored pointer. But wait, this fails to detect the case where the stored pointer stays the same and only the control block changes.std::atomic<std::shared_ptr<int>> p = std::make_shared<int>(42); void change_control_block() { auto old = p.load(); auto empty = std::shared_ptr<int>(); // Replace with an indulgent shared pointer // with the same stored pointer. p.store({ empty, old.get() }); p.notify_all(); } void wait_for_change() { auto old = p.load(); p.wait(old); }