C++ Parallel STL

考虑一个算法,代码如下:

#include <algorithm>

void process(int& x){
    //do some calculate
}

int main()
{
    int arr[100000];
    std::for_each( arr, arr+100000, [](auto & x){ process(x); });
}

for_each对于每一个数组arr的成员,都去调用了process(int& x)。这个过程是单线程(main所在的主线程)进行的。

如果想增加性能,让多线程并行的处理,需要做一些改造。例如,创建线程1处理0-30000项,创建线程2处理30001-60000项,主线程处理剩余项。

在C++17中,可以请求算法库做并行处理。怎么请求呢?代码如下:

#include <execution>
//...
int main(){
    int arr[100000];
    std::for_each( std::execution::par, arr, arr+10000, [](auto & x){ process(x); });
}

新的重载函数多出了个指定策略的参数std::execution::par。这个参数意味着算法库可能会偷偷的创建后台线程辅助完成for_each算法。

另外还有std::execution::seq,和std::execution::par_unseq。这些都是算法库预定义的常量。

因为标准库算法都会涉及到对容器和元素的读写操作,在多线程条件下,就会有数据竞争问题。数据竞争的解决,是库的用户责任。这意味着有时候就需要用互斥量,内存模型等机制保护数据的完整性。

例如:下面这段代码,程序可能要挂掉了。在多线程环境下,对共享的资源v的插入会出现不可预知的错误。

int a[] = {0,1,3,4,5,6,7,8,9};
std::vector<int> v;
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) {
  v.push_back(i*2+1); // 错误:数据竞争
});

最直接的解决方式,加锁保护,代码如下:

int a[] = {0,1,3,4,5,6,7,8,9};

std::vector<int> v;
std::mutex m;

std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) {
  std::lock_guard<std::mutex> guard(m);  //互斥量保护v
  v.push_back(i*2+1); 
});
  

有三种并行策略,各个含义如下:

std::execution::seq
调用者线程单线程方式,以不确定的顺序访问元素
std::execution::par
多线程(由库隐式的创建线程)方式,在每个线程中,以不确定的顺序访问元素
std::execution::par_unseq
multiple threads and may be vectorized - calls are unsequenced with respect to each other and possibly interleaved

我完全没懂,需要再研究。什么是“不确定顺序的“(indeterminately sequenced)?什么是“向量化的”(vectorized)?什么是交互的“interleaved”?都是什么鬼?

posted @ 2018-03-13 10:42  thomas76  阅读(3508)  评论(1编辑  收藏  举报