本文为《C++ Concurrency in Action》 读书笔记,对其中的一些知识点进行总结。阅读这本书前建议先阅读《Effective C++》
使用同步操作简化代码
使用“期望”的函数化编程
术语函数化编程(functional programming)引用于一种编程方式,这种方式中的函数结果只依 赖于传入函数的参数,并不依赖外部状态。
快速排序 FP(函数化)模式版
以下是对于快速排序的单线程实现方式:
template<typename T>
std::list<T> sequential_quick_sort(std::list<T> input)
{
//递归出口
if(input.empty())
{
return input;
}
std::list<T> result;
result.splice(result.begin(),input,input.begin()); // 将中间值先放到结果集中
T const& pivot=*result.begin();
auto divide_point=std::partition(input.begin(),input.end(),
[&](T const& t){return t<pivot;}); //将剩下的元素按照中介值进行划分
std::list<T> lower_part;
lower_part.splice(lower_part.end(),input,input.begin(),
divide_point);
auto new_lower(
sequential_quick_sort(std::move(lower_part))); 递归指向前半部分
auto new_higher(
sequential_quick_sort(std::move(input))); // 递归执行后半部分
result.splice(result.end(),new_higher); // 将后半部分放到中间值的后面
result.splice(result.begin(),new_lower); // 将前半部分放到中间值的前面
return result;
}
快速排序 FP模式线程强化版
template<typename T>
std::list<T> parallel_quick_sort(std::list<T> input)
{
//递归出口
if(input.empty())
{
return input;
}
std::list<T> result; //结果集
result.splice(result.begin(),input,input.begin()); //第一个元素作为中间值放入到结果集中
T const& pivot=*result.begin();
auto divide_point=std::partition(input.begin(),input.end(),
[&](T const& t){return t<pivot;}); //按照中间值对列表进行划分
std::list<T> lower_part;
lower_part.splice(lower_part.end(),input,input.begin(),
divide_point);
std::future<std::list<T> > new_lower( // 开创一个线程去计算前半部分
std::async(¶llel_quick_sort<T>,std::move(lower_part)));
auto new_higher(
parallel_quick_sort(std::move(input))); // 主线程继续计算后半部分
result.splice(result.end(),new_higher); // 将各个线程计算的记过合并
result.splice(result.begin(),new_lower.get()); // 主线程从新开创的线程中获得新计算的结果,并合并到结果集。
return result;
}
std::async() 会启动一个新 线程,这样当你递归三次时,就会有八个线程在运行了;当你递归十次(对于大约有1000个元 素的列表),如果硬件能处理这十次递归调用,你将会创建1024个执行线程。当运行库认为这 样做产生了太多的任务时(也许是因为数量超过了硬件并发的最大值),运行库可能会同步的切 换新产生的任务。当任务过多时(已影响性能),这些任务应该在使用get()函数获取的线程上运 行,而不是在新线程上运行,这样就能避免任务向线程传递的开销。