The following code should terminate in much less than 1s in most cases:
#include <atomic>
#include <chrono>
#include <future>
#include <stop_token>
#include <thread>
using namespace std::chrono_literals;
std::atomic_bool p2_is_set{false};
std::promise<void> p2;
int main() {
std::jthread set_p2([](const std::stop_token& token) {
p2.set_value_at_thread_exit();
p2_is_set = true;
p2_is_set.notify_one();
while (!token.stop_requested()) {
std::this_thread::sleep_for(100ms);
}
});
p2_is_set.wait(false);
p2.get_future().wait_for(0ms); // this hangs
set_p2.request_stop();
}
Unfortunately, it hangs in p2.get_future().wait_for(0ms) indefinitely, and I wonder why. I can reproduce the issue in MSVC 17.10 (https://godbolt.org/z/a3MfhWfTj), but not in other compilers.
Some additional debugging suggests p2.get_future().wait_for is waiting for an internal std::mutex - which implies the actual timeout value should not matter. That mutex is owned by the thread which called p2.set_value_at_thread_exit(). Specifically, p2._MyPromise._State._Assoc_state->_Mtx is unlocked before p2.set_value_at_thread_exit() and still locked after.
Knowing that, it is easy to see why this code seems to work but actually just crashes with an 0xc0000409 exit code:
#include <future>
int main() {
std::promise<void> p;
p.set_value_at_thread_exit();
p.get_future().wait();
}
This seems to be an MSVC/STL bug. Microsoft acknowledges as much in https://developercommunity.visualstudio.com/t/After-calling-std::promise::set_value_at/10205605. At the same time, fixing the bug would break ABI compatibility, which is why they are putting off a fix for now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With