C++使用std::async与std::lock_guard时素数计数结果异常问题
问题根本原因
你遇到的结果不稳定和std::lock_guard完全无关,问题出在你没有等待所有异步任务执行完成,就提前读取了count变量的值返回,甚至还存在野指针访问的未定义行为:
std::async启动异步任务后,你只是把返回的std::future存入了容器,没有做任何等待操作就直接返回了栈上的count变量。此时部分异步任务还没有执行完成,自然还没来得及对count做累加操作。- 更严重的是,
count是countPrimesAsync函数的栈变量,函数返回后栈空间就会被回收,还没执行完的异步任务持有的count指针会变成野指针,后续对野指针的写操作属于完全的未定义行为,结果随机偏差、程序崩溃都有可能出现。
修复方案
只需要在返回count前遍历所有std::future,调用wait()等待所有异步任务执行完成即可,同时建议把存储future的静态全局容器改成函数内局部变量,避免重复调用函数时容器内残留旧的future:
int countPrimesAsync(const long long limit) { int count = 0; // 改成局部变量,不需要静态全局 std::vector<std::future<void>> futures; for(long i = 2; i < limit; ++i) { futures.push_back(std::async(std::launch::async, countPrimesHelper, &count, i)); } // 等待所有异步任务执行完成 for (auto& fut : futures) { fut.wait(); } return count; }
另外你当前的实现性能问题非常严重:每个数字都单独启动一个线程,上限稍大就会创建成百上千个线程,线程调度、创建销毁的开销会远大于素数判断的计算开销,实际执行速度会比串行版本慢几十倍。建议优化为按区间拆分任务,总共只启动和CPU核心数相当的线程数即可。
内容的提问来源于stack exchange,提问作者iridiumcc
相关产品推荐
相关产品推荐

