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()函数。

 1 //实现标准库头文件<numeric>中accumulate函数的并行版本
 2 #include <iostream>
 3 #include <thread>
 4 #include <numeric>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <functional>
 8 #include <utility>
 9
10 using std::thread;
11 using std::vector;
12 using std::accumulate;
13 using std::cout;
14 using std::endl;
15
16 template <typename Iterator, typename T> class Accum
17 {
18 public:
19     void operator() (Iterator first, Iterator last, T &sum)
20     {
21         sum = std::accumulate(first, last, sum);
22     }
23 };
24
25 template <typename Iterator, typename T>
26 T ParallelAccum(Iterator first, Iterator last, T &sum)
27 {
28     //计算迭代器中包含的元素数量
29     const unsigned int len = std::distance(first, last);
30     //若迭代器中没有元素则直接返回
31     if (!len)
32     {
33         return sum;
34     }
35     //每个线程处理的元素的最小数量
36     const unsigned int min_per_thread = 25;
37     //获取线程的最大数量,向上取整
38     const unsigned int max_thread = (len - 1 + min_per_thread) / min_per_thread;
39     //获取机器支持的并发线程数
40     const unsigned int hardware_thread = thread::hardware_concurrency();
41     //取上述两者的较小值,同时避免线程数过少
42     const unsigned int num_thread = std::min((hardware_thread != 0 ? hardware_thread : 2), max_thread);
43     //最终实际上每个线程处理的元素个数
44     const unsigned int block_size = len / num_thread;
45     //保存每个线程累加的结果
46     vector<T> results(num_thread);
47     //启动比num_thread - 1个线程,因为main函数本身已开启一个线程
48     vector<thread> threads(num_thread - 1);
49     //
50     cout << "Number of elements: " << len << endl;
51     cout << "Hardware concurrency: " << hardware_thread << endl;
52     cout << "Maximum number of threads: " << max_thread << endl;
53     cout << "Number of threads: " << num_thread << endl;
54     cout << "Block size: " << block_size << endl;
55     cout << "Started parallel calculating..." << endl;
56     //开始并行计算
57     Iterator block_begin = first;
58     for (unsigned int i = 0; i < (num_thread - 1); ++i)
59     {
60         Iterator block_end = block_begin;
61         //将迭代器向前推进一个块,到达当前块的末尾位置
62         std::advance(block_end, block_size);
63         //传递参数,通常情况下thread的构造函数将复制所提供的参数,需要将模板参数转为引用
64         threads[i] = thread(Accum<Iterator, T>(), block_begin, block_end, std::ref(results[i]));
65         block_begin = block_end;
66     }
67     //处理最后一个线程,由于block_size = len / num_thread得到的结果不一定为整数,该线程处理剩余的所有元素
68     Accum<Iterator, T>()(block_begin, last, results[num_thread - 1]);
69     //对threads中所有线程调用join()
70     std::for_each(threads.begin(), threads.end(), std::mem_fn(&thread::join));
71     //
72     return accumulate(results.begin(), results.end(), sum);
73 }
74
75 int main()
76 {
77     vector<int> i_vec;
78     int sum = 0;
79     for (int i = 1; i != 501; ++i)
80     {
81         i_vec.push_back(i);
82     }
83     sum = ParallelAccum(i_vec.cbegin(), i_vec.cend(), sum);
84     cout << "sum = " << sum << endl;
85     system("pause");
86     return 0;
87 }
时间: 2024-10-22 03:04:12

c++多线程编程:实现标准库accumulate函数的并行计算版本的相关文章

2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,

 1信号产生原因 2.进程处理信号行为 manpage里信号3中处理方式: SIG_IGN SIG_DFL                                            默认Term动作 a signal handling function 进程处理信号 A默认处理动作 term   中断 core    core(调试的时候产生) gcc –g file.c ulimit –c 1024 gdb a.out core ign      忽略 stop     停止

c/c++ 标准库 bind 函数 详解

标准库 bind 函数 详解 bind函数:接收一个函数名作为参数,生成一个新的函数. auto newCallable = bind(callbale, arg_list); arg_list中的参数可能包含入_1, _2等,这些是新函数newCallable的参数. 在这篇博客lambda 表达式 介绍 中,讨论了find_if的第三个参数的问题,当时是用lambda表达式解决的,有了bind函数后,也可以用bind函数解决. 解决办法:bind(check_size, _1, sz) au

转 Lua标准库: table函数, 数学函数, 字符串函数/格式化/配对, WoW新增函数, 函数别名

这里只介绍和插件编写比较有关的几个函数. 详细的Lua手册请参照Lua Reference Manual 5.1. assert(value) - 检查一个值是否为非nil, 若不是则(如果在wow.exe打开调试命令)显示对话框以及输出错误调试信息 collectgarbage() - 垃圾收集器. (新增于1.10.1) date(format, time) - 返回当前用户机器上的时间. error("error message",level) - 发生错误时,输出一条定义的错误

实现C++标准库string类的简单版本

后续待更新. 1 #ifndef STRING_H 2 #define STRING_H 3 4 #include <cassert> 5 #include <utility> 6 #include <iostream> 7 8 namespace jz 9 { 10 11 /************************************************************************/ 12 /* 重新实现C风格字符串处理函数 */

java多线程编程——线程同步之同步函数

如何找出线程安全问题: 1.明确那些代码块是多线程运行代码 2.明确共享数据 3.明确多线程运行代码中哪些语句是操作共享数据的 同步函数示例: class Save{ private int sum; public synchronized void add(int n){ sum+=n; System.out.println("sum="+sum); } } class Cus implements Runnable{ private Save b=new Save(); publi

C标准库pow函数精度问题。

#include <stdio.h> int main () { int temp,i; double a=2.4568; unsigned char b[5]; for(i=0;i<5;i++) { temp=(int)a; b[i]=temp+'0'; a=(a-temp)*10; printf("%f %d\n",a,(int)a); } b[5]='\0'; puts(b); } 运行结果: 运行结果: 4.568000 4 5.680000 5 6.8000

练习了下C标准库的函数

#include<stdio.h>  2 #include<string.h>  3 #include<stdlib.h>  4 #include <time.h>  5 int main()  6 {  7 int c=5,d;  8 char a[10]={"1abe"},b[8]={"1cdefg"};  9 //strncpy(a,b,3*sizeof(char));//strncpy复制字符串,删除原字符串 

c运行库、c标准库、windows API的区别和联系

C运行时库函数C运行时库函数是指C语言本身支持的一些基本函数,通常是汇编直接实现的.  API函数API函数是操作系统为方便用户设计应用程序而提供的实现特定功能的函数,API函数也是C语言的函数实现的. 区别他们之间区别是:API函数是针对操作系统的,C语言运行时函数则是针对C语言本身的. ·1.运行时库就是 C run-time library,是C而非C++语言世界的概念.     取这个名字就是因为你的C程序运行时需要这些库中的函数. ·2.C语言是所谓的“小内核”语言,就其语言本身来说很

(转)c运行库、c标准库、windows API的区别和联系

C运行时库函数C运行时库函数是指C语言本身支持的一些基本函数,通常是汇编直接实现的.  API函数API函数是操作系统为方便用户设计应用程序而提供的实现特定功能的函数,API函数也是C语言的函数实现的. 区别他们之间区别是:API函数是针对操作系统的,C语言运行时函数则是针对C语言本身的. ·1.运行时库就是 C run-time library,是C而非C++语言世界的概念.     取这个名字就是因为你的C程序运行时需要这些库中的函数. ·2.C语言是所谓的“小内核”语言,就其语言本身来说很