OpenMP: использование модифицированной переменной

kataich

Я новичок в OpenMP. Помогите разрешить следующий вопрос.
Здесь, на странице 11 в самом конце написано:
Since each thread is executing part of the iterations of the do-loop and the updates of
the modifications made to the variables are not ensured until the end of the work-sharing
construct, the following example will not work correctly using the !$OMP DO/!$OMP END
DO directive-pair for its parallelization:

real(8) :: A(1000 B(1000)

do i = 1, 1000
B(i) = 10 * i
A(i) = A(i) + B(i)
enddo

because the correct value of the matrix B is not ensured until the end of the work-
sharing construct !$OMP END DO.
Как обходить такую проблему в случае, если я не хочу обращаться к данным, за которые ответственен другой тред,
а только к своим данным ( как в случае выше)?
Очевидное решение, разбить цикл выше на два, где сначала инициализируется массив B, а затем изменяется массив
A. К сожалению, к моему случаю такой вариант не подходит в виду огромного количества таких циклов. Можно ли это исправить как-нибудь по-другому?

conv3rsje

Навскидку
real(8) :: A(1000 B(1000)
real(8) :: tmp

!$omp parallel private(tmp)
do i = 1, 1000
tmp = 10 * i
B(i) = tmp
A(i) = A(i) + tmp
enddo

Понятно что несколько через задницу, но зато работать будет ;)

kataich

Да, безусловно, но это, как и решение с разбиением цикла в первом посте, требует изменение всех таких мест, а их довольно много.
Ситуация такая, что есть примерно следующая структура:

CYCLE_1

CYCLE_2

....

CYCLE_N

где CYCLE_i - некий цикл, имеющий следующую структуру

DO I = I_LEFT, I_RIGHT
.....
END FOR

Хочется определить I_LEFT и I_RIGHT для каждого треда и получить

!$OMP PARALLEL
CYCLE_1
...
CYCLE_N
!$OMP PARALLEL END

При этом не надо просматривать каждый цикл.

conv3rsje

Кстати, у меня есть подозрение что на это можно забить.
Проверил сейчас на сишном коде и gcc-шном openmp - код как в первом посте работает как надо.
Так что можно проверить конкретную реализацию и забить.
Что-то мне подсказывает, что в когда я с ним работал на это забивал и без особых последствий
upd
icc 11.1 тоже работает нормально

kataich

А почему так сделано?
Почему в стандартном случае мы можем присвоить переменной a значение 10, а потом использовать ее,
а в случае с тредами нет?

geja_03

Все в порядке с циклом, можно параллелить)
http://www.openmp.org/pipermail/omp/2005/000383.html

kataich

Супер! Спасибо большое. Тот же самый пример :)
Хотел бы уточнить еще пару вопросов:
1. Правильно ли я понимаю, что можно преспокойно использовать
MPI-функции внутри всех создаваемых тредов?
2. Допустим есть существующий кусок кода

INTEGER REQ
INTEGER DEST
...
MPI_ISEND(DEST, REQ)
MPI_WAITALL(1, REQ)

где DEST какой-то номер вычислительного узла, соответсвенно на DEST делается

MPI_IRECV(SRC, REQ)
MPI_WAITALL(1, REQ)

и узлы обмениваются информацией.
Допустим теперь эти два узла стали на самом деле тредами в одном mpi-процессе.
То есть теперь эти два треда исполняют тот же код, где SRC и DEST есть ранг того
узла, где эти треды исполняются. Можно ли оставлять такой код без изменений?

geja_03

Честно говоря MPI уже не помню, но я бы не рискнул делать такое смешение технологий. OpenMP это все-таки технология для SMP, а MPI для кластеров, плюс MPI с тем же успехом ложится на SMP. В общем не видно необходимости сочетать эти технологии.

kataich

Я с тобой согласен, но вот что хочется сделать.
Мы реализовали MPI-версию некоторой программы.
Далее хочется использовать то, что каждый вычислительный узел
имеет 4 ядра, а потому можно воспользоваться дополнительным
преимуществом в виде тредов на каждом вычислительном узле.
Самым простым решением было бы обойти каждый цикл и сделать
!$OMP DO/!$OMP END DO. К сожалению из-за специфики задачи такой
вариант явно не оптимальный, а более продвинутый вариант
предполагает некий обмен м/у областями, отсюда и пробема, касающаяся
вопроса 2.

geja_03

MPI должен уметь запускаться на SMP безо всяких дополнительных выкрутасов.

kataich

Нет, я, похоже, не ясно выразился.
MPI-программа запускается на MPI-кластере - все как обычно.
Но каждый вычислительный узел имеет 4 ядра, поэтому можно
для каждого MPI-процесса запустить эффективно еще 4 треда.

Serab

Ну не то, чтобы прямо спокойно (см MPI_Init_thread, например). Но race condition'ов в самом MPI не будет, главное самому дополнительных не навести (делать tag уникальным, например).

geja_03

Не-не все ясно. Я к тому, что MPI должен сам уметь порождать потоки на многоядерных нодах, причем обмен между потоками на одной ноде может происходить через прямое копирование памяти или через сетевой интерфейс на выбор.
Оставить комментарий
Имя или ник:
Комментарий: