C++线程编程-设计多线程版本的accumulate

非异常安全

// std::accumulate的并行版本,非异常安全版本
#include <numeric>
#include <iterator>
#include <thread>
#include <vector>
#include <functional>
template<typename Iterator, typename T>
struct accumulate_block
{
    void operator()(Iterator first, Iterator last, T &result)
    {
        // 计算范围和
        result = std::accumulate(first, last, result);
    }
};

template<typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
    // 计算迭代器的跳数
    const unsigned long length = std::distance(first, last);
    if (!length)    // 如果长度为0,直接返回
    {
        return init;
    }
    // 最小理论线程数量
    const unsigned long min_per_thread = 25;
    // 最大理论线程数量
    const unsigned long max_threads = (length + min_per_thread - 1) / min_per_thread;
    // 硬件核心数量
    const unsigned long hardware_threads = std::thread::hardware_concurrency();
    // 真正运行的线程数量
    const unsigned long num_threads = std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);
    // 每个线程分到的任务块的大小
    const unsigned long block_size = length / num_threads;  
    // 结果结合 - 每个线程对应一个对应的结果集合
    std::vector<T> results(num_threads);
    // 线程池
    std::vector<std::thread> threads(num_threads);
    Iterator block_start = first;
    for (unsigned long i = 0; i < (num_threads - 1); ++i)
    {
        Iterator block_end = block_start;
        // block_end 前进 block_size 个单位
        // 即block_start 到 block_end 是一个线程的工作块
        std::advance(block_end, block_size);
        threads.at(i) = \
        std::thread(accumulate_block<Iterator, T>(), \
        block_start, block_end, \
        std::ref(results.at(i)));   // 绝对引用
        // 重置下一次block_start
        block_start = block_end;
    }
    // 当前线程也要做任务,做最后一波任务
    accumulate_block()(block_start, last, results.at(num_threads - 1));
    // mem_fn把函数转换为函数对象
    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
    // 返回结果
    return std::accumulate(results.begin(), results.end(), init);
}

异常安全版本

// 使用std::packaged_task的std::accumulate的并行版本
// 解决一些异常安全
#include <numeric>
#include <future>
#include <vector>
#include <functional>
#include <thread>
template<typename Iterator, typename T>
struct accumulate_block
{
    T operator()(Iterator first, Iterator last)
    {
        return std::accumulate(first, last, T());
    }
};
template<typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
    const unsigned long length = std::distance(first, last);
    if (!length)
    {
        return init;
    }
    const unsigned long min_pre_thread = 25;
    const unsigned long max_threads =
        (length + min_pre_thread - 1) / min_pre_thread;
    const unsigned long hadrware_threads = std::thread::hardware_concurrency();
    const unsigned long num_threads =
        std::min(hadrware_threads != 0 ? hadrware_threads : 2, max_threads);
    const unsigned long block_size = length / num_threads;

    std::vector<std::future<T>> futures(num_threads - 1);
    std::vector<std::thread> threads(num_threads - 1);
    Iterator block_start = first;
    for (unsigned long i = 0; i < num_threads - 1; ++i)
    {
        Iterator block_end = block_start;
        std::advance(block_end, block_size);
        std::packaged_task<T(Iterator, Iterator)> task(accumulate_block<Iterator, T>());
        futures.at(i) = task.get_future();
        threads.at(i) = std::thread(std::move(task), block_start, block_end);
        block_start = block_end;
    }
    T last_result = accumulate_block()(block_start, last);
    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
    T result = init;
    for (unsigned long i = 0; i < num_threads - 1; ++i)
    {
        result += futures.at(i).get();
    }
    result += last_result;
    return result;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙子砰砰枪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值