您的位置:首页 > 编程语言 > C语言/C++

[C++11 并发编程] 04 - 动态选择并发线程的数量

2015-08-08 10:53 666 查看
C++标准模板库提供了一个辅助函数 - std::thread::hardware_concurrency(),通过这个函数,我们可以获取应用程序可以真正并发执行的线程数量。下面这个例子,实现了一个并发版本的std::accumulate,它将工作拆分到多个线程中,为了避免过多线程带来的开销,程序指定了每个线程处理数据的最小数量。

头文件和求和操作:

#include <thread>
#include <numeric>
#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>

template<typename Iterator,typename T>
struct accumulate_block
{
void operator()(Iterator first,Iterator last,T& result)
{
result=std::accumulate(first,last,result);
}
};
并发的求和方法如下,在我的电脑上,硬件可并发线程数为8。

template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{
unsigned long const length=std::distance(first,last);

// 若输入数据为空,则返回初始值
if(!length)
return init;

// 计算所需要的最大线程数量,每个线程至少计算25个数据
unsigned long const min_per_thread=25;
unsigned long const max_threads=
(length+min_per_thread-1)/min_per_thread;

// 获取硬件可并发线程数量
unsigned long const hardware_threads=
std::thread::hardware_concurrency();

// 计算实际要创建的线程数量
unsigned long const num_threads=
std::min(hardware_threads!=0?hardware_threads:2,max_threads);

// 根据线程数量,拆分数据
unsigned long const block_size=length/num_threads;

// 创建用于存放每个线程计算结果的容器和线程
std::vector<T> results(num_threads);
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);
// 启动新线程,对一块数据进行处理
threads[i]=std::thread(
accumulate_block<Iterator,T>(),
block_start,block_end,std::ref(results[i]));
// 为下一个线程准备数据
block_start=block_end;
}

// 当启动了所有的子线程对数据进行计算,本线程就对数据的最后一块进行计算
accumulate_block<Iterator,T>()(block_start,last,results[num_threads-1]);

// 使用fore_each对所有的线程执行join操作,等待它们执行结束
std::for_each(threads.begin(),threads.end(),
std::mem_fn(&std::thread::join));

// 最后对所有的计算结果求和
return std::accumulate(results.begin(),results.end(),init);
}
main方法:

int main()
{
std::cout << "threads: " << std::thread::hardware_concurrency() << std::endl;
std::vector<int> vi;
for(int i=0;i<100;++i)
{
vi.push_back(10);
}
int sum=parallel_accumulate(vi.begin(),vi.end(),5);
std::cout<<"sum="<<sum<<std::endl;
}


程序执行结果如下:

threads: 8
sum=1005


线程的标识符的类型为std::thread::id,有两种方法可以获取线程的标示符,一种是通过调用关联到线程的std::thread对象的get_id()方法,另一种方法是在线程内调用std::this_thread::get_id()。线程标识符通常用于区分主线程和子线程,在某些情况下主线程中可以做一些特定的操作

std::thread::id master_thread;
void some_core_part_of_algorithm()
{
if(std::this_thread::get_id()==master_thread)
{
do_master_thread_work();
}
do_common_work();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: