Ошибка openmp с радиальным вычислением
#pragma omp parallel for schedule(static) default(none)
for(int row = 0; row < m_height; row++)
{
for(int col = 0; col < m_width; col++)
{
int RySqr, RxSqr;
SettingSigmaN(eta, m_RxInitial + col, m_RyInitial + row , RxSqr, RySqr);
FunctionUsing(RySqr,RxSqr);
}
}
void CImagePro::SettingSigmaN(int Eta, int x, int y, int &RxSqr, int &RySqr, int &returnValue)
{
int rSqr = GetRadius(x,y,RxSqr,RySqr);
returnValue = GetNumberFromTable(rsqr);
}
int CImagePro::GetRadius(int x, int y, int &RxSqr, int &RySqr)
{
if (x == m_RxInitial)
{
RxSqr = m_RxSqrInitial;
if (y == m_RyInitial)
{
RySqr = m_RySqrInitial;
}
else if ( abs(y) % 2 == abs(m_RyInitial) % 2)
{
RySqr = RySqr + (y<<2) + 4; //(y+2)^2
}
}
else
{
RxSqr = RxSqr + ( x << 1) + 1; //(x+1)^2
}
return clamp(((RxSqr+RySqr)>>RAD_RES_REDUCTION),0,(1<<(RAD_RES-RAD_RES_REDUCTION))-1);
}
Итак, вот мой код, и моя проблема внутри функции GetRadius. так как у меня много потоков, каждый поток начинается в другом месте x,y. Однако я не очень понимаю, где ошибка внутри GetRadius().
я подумал, может быть, это вычисление RySqr. Можете ли вы предложить способ отладки? или ты видишь мою проблему?
ОБНОВИТЬ:
это исправило большую часть моего кода: я до сих пор не понимаю, почему между разными потоками есть скачки.
int CImagePro::GetRadius(int x, int y, int &RxSqr, int &RySqr)
{
if (x == m_RxInitial)
{
RxSqr = m_RxSqrInitial;
}
else
{
RxSqr = x * x;
}
if (y == m_RyInitial)
{
RySqr = m_RySqrInitial;
}
else if (abs(y) % 2 == abs(m_RyInitial) % 2)
{
RySqr = y * y;
}
return clamp(( (RxSqr + RySqr) >> RAD_RES_REDUCTION), 0, ( 1 << (RAD_RES - RAD_RES_REDUCTION) ) - 1);
}
2 ответа
Мне действительно интересно, если эта вещь компилируется? Вы указываете default(none)
, но последовательно используйте данные членов вашего класса. Они все статичны?
Что вы можете сделать, это либо я) уйти default(none)
прочь, что означает default(shared)
, ii) иметь общий доступ к значениям, явно разделяя их, или iii) инициализировать переменные, которые вы используете внутри параллельной области, чтобы каждый поток имел свою собственную частную копию, скажем, m_RxInitial
называется p_RxInitial
и т.д. Первый вариант почти гарантированно доставит вам неприятности.
Ниже показан вариант ii):
1) Создайте вспомогательный класс, содержащий все, что вам нужно передать, для вас это может быть
struct ShareData{
int s_RxInitial
/* ... */
}
2) В функции-члене, содержащей параллельное сечение, перед параллельным циклом определите
ShareData SD;
SD.s_RxInitial = m_RxInitial;
/* ... */
3) Дайте это параллельному разделу
#pragma omp parallel for schedule(static), default(none), shared(SD)
4) Используйте камеры данных SD в вызовах функций.
Я надеюсь, что это было достаточно ясно. Я был бы признателен, если бы у кого-то было более элегантное решение.
Если вы хотите частные переменные варианта iii), вы можете сказать firstprivate(SD)
вместо shared(SD)
, Это дало бы каждому потоку инициализированную (к исходным значениям) личную копию SD. Это может или не может дать некоторое преимущество в производительности, избегая последовательного доступа. У меня была похожая проблема несколько дней назад, и не было никакой разницы.
Вы не можете гарантировать порядок, в котором выполняются потоки, если вам нужно гарантировать, что вы делаете операторы if, как вы, или просто не распараллеливаете их, потому что это критический раздел.