c-OpenMP并行线程
作者:互联网
我需要并行处理此循环,尽管我想使用它是一个好主意,但我以前从未研究过它们.
#pragma omp parallel for
for(std::set<size_t>::const_iterator it=mesh->NEList[vid].begin();
it!=mesh->NEList[vid].end(); ++it){
worst_q = std::min(worst_q, mesh->element_quality(*it));
}
在这种情况下,循环不会并行化,因为它使用迭代器,并且编译器无法
了解如何拆分.
你能帮助我吗?
解决方法:
OpenMP要求for循环的并行控制谓词具有以下关系运算符之一:< ;、< =,>或> =.只有随机访问迭代器才提供这些运算符,因此OpenMP并行循环仅适用于提供随机访问迭代器的容器. std :: set仅提供双向迭代器.您可以使用显式任务来克服该限制.减少可以通过首先部分减少每个线程变量的私有值,然后全局减少部分值来执行.
double *t_worst_q;
// Cache size on x86/x64 in number of t_worst_q[] elements
const int cb = 64 / sizeof(*t_worst_q);
#pragma omp parallel
{
#pragma omp single
{
t_worst_q = new double[omp_get_num_threads() * cb];
for (int i = 0; i < omp_get_num_threads(); i++)
t_worst_q[i * cb] = worst_q;
}
// Perform partial min reduction using tasks
#pragma omp single
{
for(std::set<size_t>::const_iterator it=mesh->NEList[vid].begin();
it!=mesh->NEList[vid].end(); ++it) {
size_t elem = *it;
#pragma omp task
{
int tid = omp_get_thread_num();
t_worst_q[tid * cb] = std::min(t_worst_q[tid * cb],
mesh->element_quality(elem));
}
}
}
// Perform global reduction
#pragma omp critical
{
int tid = omp_get_thread_num();
worst_q = std::min(worst_q, t_worst_q[tid * cb]);
}
}
delete [] t_worst_q;
(我假设mesh-> element_quality()返回双精度值)
一些关键点:
>循环仅由一个线程串行执行,但是每次迭代都会创建一个新任务.这些很可能由空闲线程排队等待执行.
>在单个构造的隐式屏障处等待的空闲线程一开始创建就开始消耗任务.
>它所指向的值在任务主体之前被取消引用.如果在任务主体中取消引用,它将是firstprivate,并且将为每个任务(即在每次迭代中)创建迭代器的副本.这不是您想要的.
>每个线程在其t_worst_q []的私有部分中执行部分缩减.
>为了防止由于错误共享而导致的性能下降,每个线程访问的t_worst_q []元素被分隔开,从而以单独的缓存行结尾.在x86 / x64上,高速缓存行为64字节,因此线程号乘以cb = 64 / sizeof(double).
>全局最小化减少是在关键构造内部执行的,以防止badest_q被多个线程一次访问.这仅出于说明目的,因为减少也可以通过并行区域之后的主线程中的循环来执行.
请注意,显式任务需要支持OpenMP 3.0或3.1的编译器.这排除了所有版本的Microsoft C/C++编译器(仅支持OpenMP 2.0).
标签:c,performance,parallel-processing,openmp 来源: https://codeday.me/bug/20191009/1880413.html