以下代码在应用OpenMP并行化之前像魅力一样运行。实际上,以下代码处于无限循环状态!我确信这是因为我对OpenMP指令的错误使用造成的。你能告诉我正确的方法吗?非常感谢你。
#pragma omp parallel for
for (int nY = nYTop; nY <= nYBottom; nY++)
{
for (int nX = nXLeft; nX <= nXRight; nX++)
{
// Use look-up table for performance
dLon = theApp.m_LonLatLUT.LonGrid()[nY][nX] + m_FavoriteSVISSRParams.m_dNadirLon;
dLat = theApp.m_LonLatLUT.LatGrid()[nY][nX];
// If you don't want to use longitude/latitude look-up table, uncomment the following line
//NOMGeoLocate.XYToGEO(dLon, dLat, nX, nY);
if (dLon > 180 || dLat > 180)
{
continue;
}
if (Navigation.GeoToXY(dX, dY, dLon, dLat, 0) > 0)
{
continue;
}
// Skip void data scanline
dY = dY - nScanlineOffset;
// Compute coefficients as well as its four neighboring points' values
nX1 = int(dX);
nX2 = nX1 + 1;
nY1 = int(dY);
nY2 = nY1 + 1;
dCx = dX - nX1;
dCy = dY - nY1;
dP1 = pIRChannelData->operator [](nY1)[nX1];
dP2 = pIRChannelData->operator [](nY1)[nX2];
dP3 = pIRChannelData->operator [](nY2)[nX1];
dP4 = pIRChannelData->operator [](nY2)[nX2];
// Bilinear interpolation
usNomDataBlock[nY][nX] = (unsigned short)BilinearInterpolation(dCx, dCy, dP1, dP2, dP3, dP4);
}
}
答案 0 :(得分:4)
不要将它嵌得太深。通常,只需一个指令即可确定并行化的好点。
一些评论,可能是您问题的根源:
#pragma omp parallel default(shared) // Here you open several threads ...
{
#pragma omp for
for (int nY = nYTop; nY <= nYBottom; nY++)
{
#pragma omp parallel shared(nY, nYBottom) // Same here ...
{
#pragma omp for
for (int nX = nXLeft; nX <= nXRight; nX++)
{
(从概念上讲)你打开了许多线程,在每个线程中你都会在for循环中再次打开多个线程。对于for循环中的每个线程,你再次打开多个线程,对于每个线程,你再次打开许多线程for for循环。
模式匹配单词中的(thread (thread)*)+
;应该只有thread+
只做一个并行。不要在外循环上进行细粒度和并行化,每个线程应尽可能长时间运行:
#pragma omp parallel for
for (int nY = nYTop; nY <= nYBottom; nY++)
{
for (int nX = nXLeft; nX <= nXRight; nX++)
{
}
}
避免线程之间的数据和缓存共享(线程不应该在数据上太精细化的另一个原因)。
如果它运行稳定且速度很快,您可以根据OpenMP参考卡使用不同的调度算法对其进行微调。
并将您的变量声明放在您真正需要它们的位置。不要覆盖兄弟线程读取的内容。
答案 1 :(得分:3)
您还可以有效地折叠多个循环。循环条件有限制:它们必须是独立的。不仅如此,并非所有编译器都支持“崩溃”lexem。 (对于使用OpenMP的gcc,它可以工作。)
int i,j,k;
#pragma omp parallel for collapse(3)
for(i=0; i<=N-1; i++)
for(j=0; j<=N-1; j++)
for(k=0; k<=N-1; k++)
{
// something useful...
}
答案 2 :(得分:2)
在实践中,通常最有效的是并行化最外层循环。并行化所有内部循环可能会给你太多线程(虽然OpenMP坚持使用硬件执行单元的数量,否则没有说明)。更重要的是 - 并行化内部循环很可能会经常创建和销毁线程,这是一项昂贵的操作。您的CPU将执行线程API调用而不是您的工作负载。
不是真正的答案,但我想我会分享经验。
答案 3 :(得分:2)
内部循环中分配的所有变量都存在写安全性问题。每个线程都会尝试为相同的变量赋值,很可能你会得到垃圾。例如,两个线程可能同时更新dLon
,导致线程1将线程2的值传递给Navigation.GeoToXY(dX, dY, dLon, dLat, 0)
。由于您在循环中调用其他方法,因此在垃圾参数上调用的那些方法可能不会终止。
要解决此问题,请在应用omp parallel for
后立即在外部循环中声明局部变量,或者使用private
之类的firstprivate
子句使OpenMP自动为每个变量创建局部变量线。在firstprivate
的情况下,它将复制初始化的全局值。例如,
int dLon = 0;
#pragma omp parallel for firstprivate(dLon) // dLon = 0 for each thread
for (...)
{
// each thread has it's own dLon variable so there's no clash in writing
dLon = ...;
}
点击此处查看有关条款的详情:https://computing.llnl.gov/tutorials/openMP/