#include <algorithm>
#include <future>
#include <iostream>
#include <numeric>
#include <random>
#include <thread>
#include <utility>
#include <vector>
static std::mt19937 mt;
std::uniform_real_distribution<double> dist(0, 100);
// Compute the sum of a range of elements
double accum(double *beg, double *end) {
return std::accumulate(beg, end, 0.0);
}
// Divide the data into 4 parts
// Use a separate part to process each subset
// Using std::async
double add_paralel(std::vector<double> &vec) {
// First element of the vector
auto vec0 = &vec[0];
// Number of elements
auto vsize = vec.size();
// Start the threads
// Pass the subset's range as argument to the task function
auto fut1 = std::async(std::launch::async, accum, vec0, vec0 + vsize / 4);
auto fut2 = std::async(std::launch::async, accum, vec0 + vsize / 4,
vec0 + 2 * vsize / 4);
auto fut3 = std::async(std::launch::async, accum, vec0 + 2 * vsize / 4,
vec0 + 3 * vsize / 4);
auto fut4 =
std::async(std::launch::async, accum, vec0 + 3 * vsize / 4, vec0 + vsize);
// Reduce step
return fut1.get() + fut2.get() + fut3.get() + fut4.get();
}
// Using std::packaged_task
double add_parallel_2(std::vector<double> &vec) {
using task_type = double(double *, double *);
std::packaged_task<task_type> ptask1(accum);
std::packaged_task<task_type> ptask2(accum);
std::packaged_task<task_type> ptask3(accum);
std::packaged_task<task_type> ptask4(accum);
auto fut1 = ptask1.get_future();
auto fut2 = ptask2.get_future();
auto fut3 = ptask3.get_future();
auto fut4 = ptask4.get_future();
auto vec0 = &vec[0];
auto vsize = vec.size();
std::thread thr1(std::move(ptask1), vec0, vec0 + vsize / 4);
std::thread thr2(std::move(ptask2), vec0 + vsize / 4, vec0 + 2 * vsize / 4);
std::thread thr3(std::move(ptask3), vec0 + 2 * vsize / 4,
vec0 + 3 * vsize / 4);
std::thread thr4(std::move(ptask4), vec0 + 3 * vsize / 4, vec0 + vsize);
thr1.join();
thr2.join();
thr3.join();
thr4.join();
return fut1.get() + fut2.get() + fut3.get() + fut4.get();
}
int main() {
// populate a vector with elements 1, 2 ... 16
std::vector<double> vec(16);
std::iota(vec.begin(), vec.end(), 1.0);
// populate a vector with 10,000 random elements
std::vector<double> vrand(10'000);
std::generate(vrand.begin(), vrand.end(), [&vrand]() { return dist(mt); });
std::cout << "Sum of first 16 ints: " << add_parallel_2(vec) << '\n';
std::cout << "Sum of 10,000 random nums: " << add_parallel_2(vrand) << '\n';
}