VS2022中std::future<T>::get()触发运行时错误的原因排查
std::promise多次调用set_value导致abort()异常分析(C++20 VS2022)
你在C++20中使用std::promise和std::future结合std::jthread获取素数计算结果时,第二次迭代调用is_prime.get()触发运行时abort()错误,第一次迭代正常输出3。
问题代码
void IsPrime(uint64_t check, std::promise<bool> is_prime) { if (check == 2) is_prime.set_value(true); if (check < 2 || (check % 2 == 0) || (check % 5 == 0)) is_prime.set_value(false); for (uint64_t chase = 3; chase <= sqrt(check); chase += 2) if (check % chase == 0) is_prime.set_value(false); is_prime.set_value(true); } int main() { for (int i = 3; i < 100; i += 2) { std::promise<bool> prime_promise; std::future<bool> is_prime = prime_promise.get_future(); std::jthread prime_thread = std::jthread(IsPrime, i, std::move(prime_promise)); if (is_prime.get()) std::cout << i << std::endl; } return 0; }
问题根源
std::promise的核心规则是:每个promise对象只能调用一次set_value()/set_exception()等设置结果的方法,多次调用属于未定义行为,Visual Studio的标准库实现会直接触发abort()终止程序。
第一次迭代(i=3):
check==2不成立,跳过第一个if;check<2、check%2==0、check%5==0均不成立,跳过第二个if;sqrt(3)≈1.7,循环条件chase<=1.7不满足,循环不执行;- 最终仅调用一次
is_prime.set_value(true),符合规则,无异常。
第二次迭代(i=5):
check==2不成立,跳过第一个if;check%5==0成立,调用is_prime.set_value(false);sqrt(5)≈2.23,循环条件不满足,循环不执行;- 继续执行到最后一行,再次调用
is_prime.set_value(true),违反了promise只能设置一次结果的规则,触发abort()。
修复方案
修改IsPrime函数,确保每个promise仅被设置一次结果。以下两种方案均可实现:
方案1:用else if串联条件
void IsPrime(uint64_t check, std::promise<bool> is_prime) { if (check == 2) { is_prime.set_value(true); } else if (check < 2 || (check % 2 == 0) || (check % 5 == 0)) { is_prime.set_value(false); } else { bool prime = true; for (uint64_t chase = 3; chase <= sqrt(check); chase += 2) { if (check % chase == 0) { prime = false; break; } } is_prime.set_value(prime); } }
方案2:set_value后立即return
void IsPrime(uint64_t check, std::promise<bool> is_prime) { if (check == 2) { is_prime.set_value(true); return; } if (check < 2 || (check % 2 == 0) || (check % 5 == 0)) { is_prime.set_value(false); return; } for (uint64_t chase = 3; chase <= sqrt(check); chase += 2) { if (check % chase == 0) { is_prime.set_value(false); return; } } is_prime.set_value(true); }
两种方案都能保证每个std::promise仅被设置一次结果,避免触发未定义行为。
内容的提问来源于stack exchange,提问作者Donotalo
相关产品推荐
相关产品推荐

