c++多线程编程:实现标准库accumulate函数的并行计算版本
今天使用c++实现了标准库头文件<numeric>中的accumulate函数的并行计算版本,代码如下,注释写的比较详细,仅对其中几点进行描述:
①该实现假定不发生任何异常,故没有对可能产生的异常进行处理
②第42行的语句:
const unsigned int num_thread = std::min((hardware_thread != 0 ? hardware_thread : 2), max_thread);
要运行的线程数是计算出的最大线程数和硬件线程数量的较小值。这是因为若运行的线程数超出了硬件支持的范围,CPU的上下文切换会降低性能。又因为hardware_thread的值可能为0,在这种情况下用户需要自行替换线程的数量,在代码中为2,因为在单核的机器上运行过多的线程会导致性能降低,但过少的线程也会使用户错过可用的并发。
③第44行计算每个线程操作的元素个数时算式可能无法整除,但无须担心,因为最后一个线程将会处理剩下的所有元素,如第68行语句所示:
Accum<Iterator, T>()(block_begin, last, results[num_thread - 1]);
④注意第64行的语句:
threads[i] = thread(Accum<Iterator, T>(), block_begin, block_end, std::ref(results[i]));
传给线程执行的函数的第三个参数增加了std::ref(),该函数包含在头文件<functional>中。在一般情况下,thread对象的构造函数只是简单地拷贝用户提供的参数,然后传递给线程关联的可调用对象。也就是说,该可调用对象接收的是该参数的副本,对其所作的修改无法影响到最初用户所传递的参数。若需要接收参数的引用版本,则需要使用std::ref()函数。
//实现标准库头文件<numeric>中accumulate函数的并行版本
#include <iostream>
#include <thread>
#include <numeric>
#include <algorithm>
#include <vector>
#include <functional>
#include <utility> using std::thread;
using std::vector;
using std::accumulate;
using std::cout;
using std::endl; template <typename Iterator, typename T> class Accum
{
public:
void operator() (Iterator first, Iterator last, T &sum)
{
sum = std::accumulate(first, last, sum);
}
}; template <typename Iterator, typename T>
T ParallelAccum(Iterator first, Iterator last, T &sum)
{
//计算迭代器中包含的元素数量
const unsigned int len = std::distance(first, last);
//若迭代器中没有元素则直接返回
if (!len)
{
return sum;
}
//每个线程处理的元素的最小数量
const unsigned int min_per_thread = ;
//获取线程的最大数量,向上取整
const unsigned int max_thread = (len - + min_per_thread) / min_per_thread;
//获取机器支持的并发线程数
const unsigned int hardware_thread = thread::hardware_concurrency();
//取上述两者的较小值,同时避免线程数过少
const unsigned int num_thread = std::min((hardware_thread != ? hardware_thread : ), max_thread);
//最终实际上每个线程处理的元素个数
const unsigned int block_size = len / num_thread;
//保存每个线程累加的结果
vector<T> results(num_thread);
//启动比num_thread - 1个线程,因为main函数本身已开启一个线程
vector<thread> threads(num_thread - );
//
cout << "Number of elements: " << len << endl;
cout << "Hardware concurrency: " << hardware_thread << endl;
cout << "Maximum number of threads: " << max_thread << endl;
cout << "Number of threads: " << num_thread << endl;
cout << "Block size: " << block_size << endl;
cout << "Started parallel calculating..." << endl;
//开始并行计算
Iterator block_begin = first;
for (unsigned int i = ; i < (num_thread - ); ++i)
{
Iterator block_end = block_begin;
//将迭代器向前推进一个块,到达当前块的末尾位置
std::advance(block_end, block_size);
//传递参数,通常情况下thread的构造函数将复制所提供的参数,需要将模板参数转为引用
threads[i] = thread(Accum<Iterator, T>(), block_begin, block_end, std::ref(results[i]));
block_begin = block_end;
}
//处理最后一个线程,由于block_size = len / num_thread得到的结果不一定为整数,该线程处理剩余的所有元素
Accum<Iterator, T>()(block_begin, last, results[num_thread - ]);
//对threads中所有线程调用join()
std::for_each(threads.begin(), threads.end(), std::mem_fn(&thread::join));
//
return accumulate(results.begin(), results.end(), sum);
} int main()
{
vector<int> i_vec;
int sum = ;
for (int i = ; i != ; ++i)
{
i_vec.push_back(i);
}
sum = ParallelAccum(i_vec.cbegin(), i_vec.cend(), sum);
cout << "sum = " << sum << endl;
system("pause");
return ;
}
c++多线程编程:实现标准库accumulate函数的并行计算版本的更多相关文章
- c/c++ 标准库 bind 函数 详解
标准库 bind 函数 详解 bind函数:接收一个函数名作为参数,生成一个新的函数. auto newCallable = bind(callbale, arg_list); arg_list中的参 ...
- Atitit 数据库 标准库 sdk 函数库 编程语言 mysql oracle attilax总结
Atitit 数据库 标准库 sdk 函数库 编程语言 mysql oracle attilax总结 1.1. 常见的编程语言以及数据库 sql内部函数库标准化库一般有以下api1 1.2. 各个 ...
- 实现C++标准库string类的简单版本
代码如下: #ifndef STRING_H #define STRING_H #include <cassert> #include <utility> #include & ...
- C标准库常用函数概要
stdio.h printf()/fprintf() printf的返回值是打印的字符数, 发生错误则返回负数 scanf()/fscanf() scanf的返回值是成功赋值的变量个数, 失败则返回E ...
- 标准库bind函数中使用占位符placeholders
placeholders ,占位符.表示新的函数对象中参数的位置.当调用新的函数对象时,新函数对象会调用被调用函数,并且其参数会传递到被调用函数参数列表中持有与新函数对象中位置对应的占位符. 举个例子 ...
- 【C++】标准库sort函数的自定义排序
自定义排序需要单独写一个compare函数 例1 LeetCode 056. Merge Intervals Given a collection of intervals, merge all ov ...
- C++11 标准库 bind 函数
bind 是什么? bind 顾名思义: 绑定 通俗来讲呢,可以这么理解有点像函数指针的意思. 资料上是这么讲的:可以将 bind 函数看做一个通用函数的适配器,它接受一个可调用对象,生成一个新的可以 ...
- C标准库pow函数精度问题。
#include <stdio.h> int main () { int temp,i; double a=2.4568; unsigned ]; ;i<;i++) { temp=( ...
- 逆向 stdio.h 函数库 fseek 函数(调试版本)
0x01 fseek 函数 函数原型:int fseek(FILE *stream, long int offset, int whence) 函数功能:设置流 stream 的文件位置为给定的偏移 ...
随机推荐
- Windows下如何安装python第三方库lxml
lxml是个非常有用的python库,它可以灵活高效地解析xml,与BeautifulSoup.requests结合,是编写爬虫的标准姿势. 参考 Windows下如何安装python第三方库lxml ...
- Spring笔记2——Spring中Bean的装配
1.引言 Spring中,对象无需自己负责查找或创建与其关联的其他对象,而是由容器负责把需要相互协作的对象引用赋予各个对象.创建应用对象之间的协作关系的行为通常称为装配(Wiring),这也是依赖注入 ...
- .net 数据缓存(二)之Redis部署
现在的业务系统越来复杂,大型门户网站内容越来越多,数据库的数据量也越来愈大,所以有了“大数据”这一概念的出现.但是我们都知道当数据库的数据量和访问过于频繁都会影响系统整体性能体验,特别是并发量高的系统 ...
- mongodb 索引的创建
mongodb 创建常用的创建索引的有 signle Field Indexes Compound multikey,创建索引就是按照索引字段把documnet 进行排序,索引只存储了document ...
- 搭建时间服务器(linux)
我们搭建集群环境的时候,时间必须是要统一的,才能保证集群数据的一致性. 一般操作是直接使用NTP,跟默认的时间服务器同步,但是最好还是让所有节点跟集群中的某台作为时间服务器的节点同步. 步骤:(节点有 ...
- Ad Exchange基本接口和功能
这里描述下一个exchange通常应该提供的接口和应该满足的功能. 接口 实时竞价接口 实时竞价接口也是最核心的接口,对接的dsp需要向exchange提供竞价地址.每次有广告请求时,exchange ...
- mathematical method
mathematical method 曲线拟合 指数 \(lnY = lna + bX\) 对数 \(Y = blnX + a\) 幂函数 \(lgY=lga+blgX\) 多元线性回归模型 回归分 ...
- 算法学习 - ST表 - 稀疏表 - 解决RMQ问题
2017-08-26 21:44:45 writer:pprp RMQ问题就是区间最大最小值查询问题: 这个SparseTable算法构造一个表,F[i][j] 表示 区间[i, i + 2 ^ j ...
- linux pgrep命令的使用
pgrep 是通过程序的名字来查询进程的工具,一般是用来判断程序是否正在运行. 常用参数 -l 列出程序名和进程ID -o 进程起始的ID -n 进程终止的ID $ ps -ef | grep mys ...
- 浏览器检测-js
昨天有一同学问我为什么attachEvent在非IE浏览器下不能起作用,我也跟他解释了一番:attachEvent是IE下独有的,只能在IE下使用,其他浏览器下应该用addEventListener来 ...