我有一个二维图像,我想计算所有颜色并将结果存储在一个数组中。我知道颜色的数量,所以我可以先设置数组的大小。我现在的问题是计数持续时间太长了。如何使用OpenMP加快计数?
我目前的序列号是
std::vector<int> ref_color_num_thread;
ref_color_num.resize(ref_color.size());
std::fill(ref_color_num.begin(), ref_color_num.end(), 0);
ref_color_num_thread.resize(ref_color.size());
std::fill(ref_color_num_thread.begin(), ref_color_num_thread.end(), 0);
for (int i = 0; i < image.width(); i++)
{
for (int j = 0; j < image.height(); j++)
{
for (int k = 0; k < (int)ref_color.size(); k++)
{
if (image(i, j, 0, 0) == ref_color[k].R && image(i, j, 0, 1) == ref_color[k].G && image(i, j, 0, 2) == ref_color[k].B)
ref_color_num_thread[k]++;
}
}
}
第一种方法是在每个循环中设置#pragma omp parallel for
(每次尝试在另一个循环中),但每次因为错误的内存访问而导致程序崩溃。我必须使用private()
作为我的载体吗?
答案 0 :(得分:3)
您正在做的是填充颜色的直方图。这与使用OpenMP在C / C ++中进行数组缩减等效。在C / C ++中,OpenMP没有内置的支持(但它在Fortran中确实存在,因为Fortran中的数组大小是已知的,在C / C ++中它只有静态数组才知道)。但是,使用OpenMP自行完成C / C ++数组缩减很容易。
#pragma omp parallel
{
std:vector<int> ref_color_num_thread_private(ref_color.size(),0);
#pragma omp for
for (int i = 0; i < image.width(); i++) {
for (int j = 0; j < image.height(); j++) {
for (int k = 0; k < (int)ref_color.size(); k++) {
if (image(i, j, 0, 0) == ref_color[k].R && image(i, j, 0, 1) == ref_color[k].G && image(i, j, 0, 2) == ref_color[k].B)
ref_color_num_thread_private[k]++;
}
}
}
#pragma omp critical
{
for(int i=0; i<(int)ref_color.size(); i++) {
ref_color_num_thread[i] += ref_color_num_thread_private[i];
}
}
}
我详细介绍了他的Fill histograms (array reduction) in parallel with OpenMP without using a critical section
我展示了如何在没有关键部分的情况下减少阵列,但它更加棘手。你应该测试第一个案例,看看它是否适合你。只要颜色数(ref_color.size())与像素数相比较小就应该很好地并行化。否则,您可能需要尝试没有关键部分的第二种情况。
答案 1 :(得分:1)
如果外部两个循环(i或j)中的一个是并行化的,则存在竞争条件,因为内部循环在向量(k)上迭代。我认为你的崩溃就是因为这个原因。
您必须重组您的计划。这不是一件容易的事,但有一个想法是每个线程都使用ref_color_num_thread
向量的本地副本。计算完成后,您可以总结所有向量。
如果k足够大以提供足够的并行性,则可以交换循环。而不是“i,j,k”,你可以按“k,i,j”的顺序迭代。如果我没有弄错的话,就没有违反的依赖关系。然后你可以并行化外部k循环,让内部i和j循环顺序执行。
<强>更新强>
pragma omp也支持减少,例如:
#pragma omp for reduction(+ : nSum)
以下是指向某些documentation的链接。
也许这可以帮助您重组您的计划。