【发布时间】:2021-11-08 08:09:07
【问题描述】:
我一直在尝试std::async。我写了一个(非常低效的)函数,它将所有素数相加到给定的限制。
如果没有std::async,该函数总是给出由ctest 单元测试判断的预期结果。使用std::async 但不使用std::lock_guard / mutex,预期值和计算值之间存在(如预期的那样)很大的偏差。使用std::lock_guard / mutex,结果仍然无法重现,并且在大约 50% 的测试中给出了正确的结果,在另外 50% 的测试中,该值相差 1-2(例如 9151 而不是 9152)。
我正在争论是否存在问题,因为我的isPrime(int) 函数引入了另一个瓶颈。或者,我认为程序(有时)在最后一个线程完成工作之前提前终止。
无论哪种情况,我都不明白为什么std::lock_guard 似乎不能保护变量计数。
// primeAsync.cc
#include <future>
#include <vector>
#include "primeAsync.h"
#include "prime.h"
// mutex for thread safety
static std::mutex s_PrimeMutex;
// handle to store futures
static std::vector<std::future<void>> s_Futures;
static void countPrimesHelper(int* count, const long long number);
// passes ctest every other time, count is off by 1-2 (e.g. 9151 instead of 9152)
int countPrimesAsync(const long long limit) {
int count = 0;
for(long i = 2; i < limit; ++i) {
s_Futures.push_back(std::async(std::launch::async, countPrimesHelper, &count, i));
}
return count;
}
// helper function for countPrimesAsync, std::async
static void countPrimesHelper(int* count, const long long number) {
if(isPrime(number)) {
const std::lock_guard<std::mutex> lock(s_PrimeMutex);
++(*count);
}
}
// prime.cc
#include <iostream>
#include <vector>
// always passes ctest
bool isPrime(const long long n) {
int mod;
for(long long m = n - 1; m > 1; --m) {
mod = n % m;
if(mod == 0) {
return false;
}
}
return true;
}
// always passes ctest
int countPrimes(const long long limit) {
int count = 0;
for(long i = 2; i < limit; ++i) {
if(isPrime(i)) {
count++;
}
}
return count;
}
【问题讨论】:
-
你在哪里等待向量中的所有期货完成?
-
线程消毒剂detects a data race here。你可能在当地有更好的象征运气。
-
您的计数变量是函数中的局部变量,它启动大量线程然后退出。因此,所有这些线程递增的计数指针指向的变量不再存在。你很幸运,它完全有效。在计数变量停止存在之前等待所有线程完成是正确的想法。
标签: c++ multithreading mutex stdasync