На форуме RSDN я встретил интересную ветку, где описывается специфическая ошибка использования функции rand() в параллельных секциях OpenMP (http://rsdn.org/forum/cpp.applied/3400925.flat). Я собираю различные ошибки, связанные с использованием технологии OpenMP для того, чтобы в дальнейшем реализовывать их диагностику в статическом анализаторе кода VivaMP. Описанная в форуме ошибка, пожалуй, слишком специфична, чтобы реализовывать правило для ее проверки и поэтому я решил просто написать о ней в блоге.
Ошибка заключается в том, что каждый параллельный поток имеет свой собственный seed и если не осуществить специальной инициализации, то функция rand() во всех потоках будет возвращать одинаковое значение. Скорее всего, это не будет желаемым результатом.
Примечание. Seed - это начальное значение, выданное генератору случайной последовательности, чтобы получить первое случайное число. Если вы присвоите seed определенное значение, последовательность чисел будет всегда повторяться, начиная с этого же самого числа.
В форуме приводился следующий пример кода:
void initMatrix(int** m, int H, int W)
{
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < H; ++i)
for (int j = 0; j < W; ++j)
m[i][j] = rand()%15;
}
}
Результатом работы такого кода является заполнение матрицы повторяющимися блоками чисел. Например, матрица 10×10, заполненная в двух потоках, может выгладить следующим образом:
Как видно, верхняя и нижняя часть матрицы, заполненные в двух разных потоках - одинаковы.
Чтобы избежать аналогичного поведения функции rand() в вашем коде следует инициализировать генератор случайных чисел в каждом параллельном потоке различными значениями. Для этого можно использовать комбинацию текущего времени с номера текущего потока.
Исправленный код будет выглядеть следующим образом:
void initMatrix(int** m, int H, int W)
{
#pragma omp parallel
{
srand(int(time(NULL)) ^ omp_get_thread_num());
#pragma omp for
for (int i = 0; i < H; ++i)
for (int j = 0; j < W; ++j)
m[i][j] = rand()%15;
}
}