TBB 免费图像 lambda 数组比较错误

TBB Free Image lambda array comparison error

我一直在 linux 上使用 Free Image Plus 玩 Thread 构建块。当从一个图像中减去另一个图像时,我一直在尝试比较顺序方法和并行方法之间的速度,但是我注意到使用并行方法时的最终结果会产生一些我现在不确定要解决的异常,并且需要一些建议.

我的问题是:为什么图像在使用并行时似乎会产生更多的数组比较错误,但在使用顺序时却可以正常工作(图像应该是黑色的,带有一些白点,所以第二个中的白色像素图像是 2 个图像像素阵列(RGBQUAD 类型)之间的比较误差。

RGBQUAD 在调用这些方法之前声明并作为全局变量。

RGBQUAD rgb;    
RGBQUAD rgb2;

https://imgur.com/Qs6G3z7 "Sequential".

for (auto y = 0; y < height; y++)
{
    for(auto x= 0; x < width; x++)
    {
        inputImage.getPixelColor(x, y, &rgb);
        inputImage2.getPixelColor(x, y, &rgb2);
        rgbDiffVal[y][x].rgbRed = abs(rgb.rgbRed - rgb2.rgbRed);
        rgbDiffVal[y][x].rgbBlue = abs(rgb.rgbBlue - rgb2.rgbBlue);
        rgbDiffVal[y][x].rgbGreen = abs(rgb.rgbGreen - rgb2.rgbGreen);
    }
}

https://imgur.com/Yd3v1ko "with TBB parallel".

parallel_for(blocked_range2d<int,int>(0,height, 0, width), [&] (const blocked_range2d<int,int>&r) {
    auto y1 = r.rows().begin();
    auto y2 = r.rows().end();
    auto x1 = r.cols().begin();
    auto x2 = r.cols().end();

    for (auto y = y1; y < y2; y++) {
        for (auto x = x1; x < x2; x++) {
            inputImage.getPixelColor(x, y, &rgb);
            inputImage2.getPixelColor(x, y, &rgb2);

            rgbDiffVal[y][x].rgbRed = abs(rgb.rgbRed - rgb2.rgbRed);
            rgbDiffVal[y][x].rgbBlue = abs(rgb.rgbBlue - rgb2.rgbBlue);
            rgbDiffVal[y][x].rgbGreen = abs(rgb.rgbGreen - rgb2.rgbGreen);
        }
    }
});

我认为这可能与在 lambda 中传递引用指针有关,该 lambda 无论如何都通过引用复制值,因为这是我能想到的唯一可能影响该过程的事情。 (RGB,RGB2)。我观察到,如果我将阻塞范围的平行线更改为高度和宽度,这就解决了问题,但是这首先打败了使用平行法的意义。

If these variables are supposed to temporarily store pixel colors, maybe you just need to move the declarations into the lambda, making variables local to each thread. – Alexey Kukanov.

变量确实被放置在 lambda 的边界之外,因此每个线程都在修改引用的变量,从而导致竞争条件,其中一个线程会尝试从变量中读取数据,而另一个线程正在修改它。

我要做的第一件事是在更新周围放置一个自旋互斥锁(存储结果的内部循环的最后三行。)这会大大减慢程序速度,但会告诉您是否您的更新存在同步问题。 (这并不明显,但是您将一些结果的相邻值存储在相同的缓存行中。测试是回答这个问题的唯一方法。)

如果是,您可以进行原子交换来更新结果,但那非常昂贵。如果没有,抱歉我没有发现你的问题。

即使这不是问题,您也可以通过使用缓存对齐的一维 blocked_range 获得更好的性能。我会留给你去做血淋淋的实施。