本文已参与「新人创作礼」活动,一起开启掘金创作之路。
在C++代码中,我们是否线程越多越好? 是否可以无限创建?如何合理的使用C++线程,带着这几个问题我们来学习下今天的这个主题
1、 标准函数 hardware_concurrency
在新版的C++中我们能够通过这个函数返回能够同时并发的线程数目,接下来我们来试一下
int main() {
static unsigned int st = std::thread::hardware_concurrency();
cout << "data==" << st << endl;
return 0;
}
看到这里是8,那这个数字的依据是什么,
看下面的图就明白了吧,也就是说在多核CPU中,返回的就是CPU的核芯数
2、实现std::accumulate
2.1 创建 accumulate_block
//accumulate函数的作用就是累加求和Iterator和可迭代对象,T是计算的结果
template<typename Iterator,typename T>
struct accumulate_block {
void operator()(Iterator fitst, Iterator last, &T result) {
//accumulate 在C++14中没办法调用到
result = std::accumulate(first, last, result);
}
};
2.1 创建 parallel_accumulate
template<typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
//计算长度
unsigned long const length = std::distance(first, last);
if (!length)
{
//如果长度为0,那就直接返回
return init;
}
//设置最小的线程数 这个可以根据自己的设备改下
unsigned long min_per_thread = 25;
//设置最大的线程数,其实我不明白为啥要这样计算,有明白的评论区留言吧
unsigned long const max_threads = (length + min_per_thread - 1) / min_per_thread;
//硬件支持的并发数
unsigned long const num_thread = std::thread::hardware_concurrency();
//计算实际要创建的线程数量
unsigned long const block_size = length / num_thread;
//计算结果的容器
std::vector<T> result(num_thread);
//保存线程的容器
std::vector<std::thread> threads(num_thread - 1);
Iterator block_start = first;
for (unsigned long i = 0; i < (num_thread - 1); ++i) {
Iterator block_end = block_start;
//block_end 表示某个迭代器,block_size 为整数。该函数的功能是将 block_end 迭代器前进或后退 n 个位置。
std::advance(block_end,block_size);
threads[i] = std::thread(accumulate_block<Iterator, T>(), block_start, block_end, std::ref(result[i]));
block_start = block_end;
}
accumulate_block<Iterator, T>() (block_start, last, result[num_thread - 1]);
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
return std::accumulate(result.begin(), result.end(), init);
};
在for循环中我们可以看到,使用std::advance来更新block_start,然后传递到accumulate_block去计算
使用简单的循环来启动线程∶block_end迭代器指向当前块的末尾,并启动一个新线程为当前块累加结果。当迭代器指向当前块的末尾时﹐启动下一个块。 对于分配不均﹐因为知道最终块是哪一个﹐那么这个块中有多少个元素就无所谓了。 当累加最终块的结果后﹐可以等待std::for_each创建线程的完成,之后使用std::accumulate将所有结果进行累加。