У меня есть некоторый код на Фортране, который был написан для научных целей.Существует два вызова условных функций, которые проверяются и выполняются последовательно.Вызовы этих функций я бы хотел распараллелить, так как они не связаны друг с другом.Тем не менее, я не уверен, как лучше это сделать.
Пример кода, который у меня есть, выглядит следующим образом:
...
if ( flag1 ) then
stat1 = func1( tm, dt, struct % a, struct % b )
if ( stat1 .gt. 0 ) then
call die_error("error message")
status = 1
return
end if
end if
if ( flag2 ) then
stat2 = func2( tm, dt, struct % a, struct % c )
if ( stat2 .gt. 0 ) then
call die_error("error message 2")
status = 1
return
end if
end if
...
Флаги flag1
и flag2
являются пользовательскимиопределено, один из них может быть правдой или оба могут быть правдой, или оба могут быть ложными, поэтому они проверяются независимо.
Аргументы функции tm
и dt
являются переменными целочисленной и двойной точности соответственно, но они не изменяются func1
или func2
.
Настраиваемый тип данных struct
содержит три массива двойной точности: a
, b
и c
.Массив struct % a
не изменяется func1
или func2
.Однако struct % b
- это , измененное func1
, а struct % c
- , измененное func2
.
В конкретном случае, когда flag1
и flag2
оба истинны, тогда func1
и func2
могут быть вызваны параллельно.Однако я не уверен в следующем:
- как правильно обращаться с пользовательским типом данных;например, нужны ли мне блокировки?
- как правильно обращаться с
struct % a
, так как он не изменяется кодом;firstprivate(struct % a)
например? - как правильно реализовать условия, поскольку я хочу только распараллелить, если
flag1
и flag2
оба истинны?
Моя попытка заключается в следующем:
...
!$omp parallel num_threads(2) firstprivate(tm, dt, struct % a) if(flag1 .and. flag2)
!$omp master
!$omp task lastprivate(stat1)
stat1 = func1( tm, dt, struct % a, struct % b )
!$omp end task
!$omp task lastprivate(stat2)
stat2 = func2( tm, dt, struct % a, struct % c )
!$omp end task
!$omp taskwait
if ( (stat1 .gt. 0) .or. (stat2 .gt. 0) ) then
call die_error("error message")
status = 1
return
end if
!$omp end master
!$omp end parallel
if ( flag1 .and. .not.flag2 ) then
stat1 = func1( tm, dt, struct % a, struct % b )
if ( stat1 .gt. 0 ) then
call die_error("error message")
status = 1
return
end if
end if
if ( flag2 .and. .not.flag1 ) then
stat2 = func2( tm, dt, struct % a, struct % c )
if ( stat2 .gt. 0 ) then
call die_error("error message 2")
status = 1
return
end if
end if
...
Несколько вопросов, которые у меня есть выше:
Нужна ли директива
!$omp master
? Следует ли использовать директиву
!$omp sections
вместо
!$omp task
? Безопасен ли мой возврат из директивы
!$omp parallel
, если либо
func1
или
func2
не удалось?