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 (), 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();
}
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./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();
}
Share
Improve this question
edited Mar 12 at 13:55
bers
asked Mar 12 at 12:23
bersbers
5,9932 gold badges46 silver badges86 bronze badges
2
|
1 Answer
Reset to default 1This seems to be an MSVC/STL bug. Microsoft acknowledges as much in https://developercommunity.visualstudio/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.
sleep_for
andwait_for
can wait longer than requested. It does not explain the issue, but it would be more correct to say "The following code is unlikely to take more than 200ms to terminate (and very unlikely much more than that)" – 463035818_is_not_an_ai Commented Mar 12 at 13:38