C++ std::thread多线程初探
字数统计:738
C++11开始正式在语言层面通过标准模板库的方式提供了std::thread来进行多线程优化,使用多线程进行并行计算是现代计算机上软件对计算进行加速的最普遍的方式。
参考:C++并发编程实战 第二版。
std::accumulate是C++ numeric头文件中提供的求和算法,其中一个最广泛的重载是传入起始迭代器,结束迭代器和初始值。
根据书中的内容,并发版accumulate如下:
#include <vector>
#include <thread>
#include <functional>
#include <numeric>
#include <iostream>
template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
if (first == last) // 长度为0时直接返回初始值
return init;
constexpr size_t min_per_thread = 25; // 当计算量很大时规定每一个块的最小计算量
const size_t length = std::distance(first, last); // distance计算两个迭代器之间的距离
const size_t max_threads = // 用范围内元素的总数量除以线程(块)中最小任务数,并保证其大于1
length / min_per_thread + 1;
const size_t hardware_threads = // 返回硬件支持的并发线程数,为0时代表无确定值
std::thread::hardware_concurrency();
const size_t num_threads = // 计算程序使用的所有线程数
std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);
const size_t block_size = length / num_threads; // 运算目标分组大小
std::vector<T> results(num_threads); // 创建线程表
/* 实际上num_threads可以等于1,此时该函数也可以确保计算的正确性 */
std::vector<std::thread> threads(num_threads - 1); // 减1是因为此时有主线程存在
/* 至此,计算出并发线程数num_threads,储存结果的容器results,线程表threads,运算块大小block_size */
Iterator block_start = first;// 块起点为容器起点
// 开始
for (size_t i = 0; i < (num_threads - 1); ++i)
{
Iterator block_end = block_start;
std::advance(block_end, block_size); // advance将迭代器(数据)移动n位(块大小)
threads[i] = std::thread( // 创建线程
[&results, block_start, block_end, i]() // 调用lambda进行计算,每次计算块大小的数据存入结果容器
{
results[i] = std::accumulate(
block_start, block_end, results[i]);
});
block_start = block_end; // 每次将起点移动到本次终点
}
results[num_threads - 1] = std::accumulate( // 计算最后一组
block_start, last, results[num_threads - 1]);
for (auto &i : threads) // 等待线程完成其执行
i.join();
return std::accumulate(results.begin(), results.end(), init); // 计算结果容器内结果的和
}
int main()
{
std::vector<int> a{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = parallel_accumulate(a.begin(), a.end(), 20);
std::cout << sum << std::endl;
}
我在原作者代码基础上将伪函数改写为lambda,for_each改为range-for并做了其他一些调整,整体与原代码保持一致。
作者提到,由于并发计算不是顺序计算,所以浮点类型的计算结果由于精度问题可能和顺序计算不一致。
并且由于迭代器指向问题,在某些类模板上不一定工作。
若无特殊声明,本人原创文章以
CC BY-SA 4.0许可协议
提供。
本站不欢迎非搜索引擎类,非个人学习类爬虫;严禁将文章直接爬取至其他站点。
若看到此条消息,说明你正在访问的网站可能是垃圾二手转载网站。
为了获得更好的浏览体验,请访问唯一原始网站:mysteriouspreserve[dot]com或blog[dot]bizwen[dot]com。