异常安全的并行 accumulate
template<typename Iterator, typename T>
struct AccumulateBlock
{
T operator()(Iterator first, Iterator last)
{
return std::accumulate(first, last, T());
}
};
class ThreadsJoiner
{
private:
std::vector<std::thread>& threads;
public:
ThreadsJoiner(std::vector<std::thread>& threads_):
threads(threads_)
{}
~ThreadsJoiner()
{
for (auto& thread : threads){
if (thread.joinable()){
thread.join();
}
}
}
};
template<typename Iterator, typename T>
T parallelAccumulate(Iterator first, Iterator last, T init)
{
size_t const length = std::distance(first, last);
if (length == 0){
return init;
}
size_t constexpr minDataNumPerThread = 25;
size_t const hardwareThreadNum = std::thread::hardware_concurrency();
size_t const neededThreadNum =
((length + minDataNumPerThread) / minDataNumPerThread);
size_t const threadNum = std::min(neededThreadNum,
(hardwareThreadNum == 0
? 2
: hardwareThreadNum));
size_t const blockSize = (length / threadNum);
std::vector<std::future<T>> futures(threadNum - 1);
std::vector<std::thread> threads(threadNum - 1);
ThreadsJoiner joiner(threads);
auto blockBegin = first;
for (size_t i = 0; i < (threadNum - 1); ++i){
auto blockEnd = blockBegin;
std::advance(blockEnd, blockSize);
std::packaged_task<T(Iterator, Iterator)> task(
(AccumulateBlock<Iterator, T>())
);
futures[i] = task.get_future();
threads[i] = std::thread(std::move(task), blockBegin, blockEnd);
blockBegin = blockEnd;
}
T lastResult = AccumulateBlock<Iterator, T>()(blockBegin, last);
T result = init;
for (auto& future : futures)
{
result += future.get();
}
result += lastResult;
return result;
}