next up previous contents
След.: Оператор SYNC IMAGES Выше: Операторы синхронизации Пред.: Операторы синхронизации   Содержание


Оператор SYNC ALL

Оператор SYNC ALL создает барьер, на котором все образы синхронизируются перед выполнением прочих операторов. Все операторы, расположенные до барьера на образе $ P$ выполняются до всех операторов, расположенных после барьера на образе $ Q$ . Если образ $ P$ модифицирует переменную до барьера, то все образы получат новое значение переменной при обращении к ней после барьера. Если образ обращается к переменной до барьера, он получит ее значение до прохождения барьера. Ниже приведен простой пример применения SYNC ALL. Образ $ 1$ читает данные и рассылает их другим образам. Первый барьер SYNC ALL гарантирует, что образ $ 1$ не помешает использованию переменной $ z$ другими образами. Второй SYNC ALL гарантирует, что не получит $ z$ до ее установки образом $ 1$ .

REAL :: z[*]

...

SYNC ALL

IF (THIS_IMAGE()==1) THEN

READ(*,*) z

DO image = 2, num_images()

SYNC ALL

z[image] = z

END DO

END IF

SYNC ALL

...

Хотя обычно синхронизация запрашивается одним и тем же оператором SYNC ALL на всех образах, это не обязательно. Дополнительная гибкость может быть полезной, например, когда разные образы исполняют разный код и время от времени обмениваются данными. Поведение при инициации программы такое, как если бы первым оператором тела программы был SYNC ALL: можно полагаться на инициализацию комассивных переменных во всех образах.

Последовательность операторов на каждом образе, выполняемая до первого оператора управления образами или между двумя таковыми, называется сегментом. Выполнение сегмента непосредственно перед выполнением оператора управления образами включает в себя выполнение всех входящих в сегмент операторов. Например, в примере выше каждый образ выполняет сегмент до первого оператора SYNC ALL, сегмент до между первым и вторым SYNC ALL и сегмент после второго SYNC ALL до конца программы.

На образе $ P$ последовательность операторов определяет последовательность сегментов $ P_i$ , $ i=1,2,\dots$ Выполнение соответствующих друг другу операторов управления образами на образах $ P$ и $ Q$ в конце сегментов $ P_i$ и $ Q_j$ может гарантировать либо предшествование $ P_i$ сегменту $ Q_{j+1}$ , либо предшествование $ Q_j$ сегменту $ P_{i+1}$ , или и то, и другое. Отсюда следует вывод о частичной упорядоченности множества всех сегментов на всех образах: сегмент $ P_i$ предшествует сегменту $ Q_j$ в том и только в том случае, если существует последовательность сегментов, начинающаяся с $ P_i$ и заканчивающаяся $ Q_j$ и такая, что каждый сегмент последовательности предшествует следующему либо потому, что он раньше идет в том же образе, либо в силу соответствующих операторов управления образами.

Пара сегментов $ P_i$ и $ Q_j$ называется неупорядоченной, если $ P_i$ не предшествует и не идет после $ Q_j$ . Например, если срединный сегмент предыдущего примера есть $ P_i$ на образе 1 и $ Q_j$ на другом образе $ Q$ , то $ P_{i-1}$ предшествует $ Q_{j+1}$ и $ P_{i+1}$ идет после $ Q_{j-1}$ , но $ P_i$ и $ Q_j$ неупорядочены.

Имеются ограничения на то, что позволено в сегменте, неупорядоченном относительно другого сегмента. Это дает компилятору возможности для оптимизации. Комассив может быть определен и к нему можно обращаться во время выполнения неупорядоченных сегментов посредством вызовов атомарных процедур (см. ниже). Кроме того, если переменная определена в сегменте образа, к ней нельзя обращаться, определять и делать неопределенной в сегменте другого образа, если эти два сегмента неупорядочены; если размещение размещаемого подобъекта комассива или связь указателя с указательным подобъектом комассива меняется в сегменте образа, этот подобъект нельзя определять и обращаться к нему в сегменте другого образа, если эти два сегмента неупорядочены; если процедура на образе $ P$ выполняется в сегментах $ P_i$ , $ P_{i+1}, \dots, P_k$ и определяет не комассивный формальный аргумент, то к переданному в процедуру фактическому аргументу нельзя обращаться или определять его на другом образе $ Q$ в сегментах $ Q_j$ , если они не предшествуют $ P_i$ , или не идут после $ P_k$ (поскольку копия фактического аргумента может быть передана в процедуру). Отсюда следует, что код внутри сегмента может быть оптимизирован с применением почти всех средств из арсенала компилятора, как если бы образ был всего один. В частности, могут применяться технологии оптимизации, перемещающие код (если отсутствуют вызовы атомарных процедур). В качестве примера недопустимой оптимизации рассмотрим код

INTEGER x(8) [*]

...

! Какие-то вычисления, использующие и меняющие x(1:7)

Поскольку другой образ может определить x(8) в сегменте, неупорядоченном по отношению к данному, компилятор не может сделать следующую замену:

INTEGER X(8)[*], TEMP(8)

...

TEMP(1:8) = X(1:8) ! Быстрее, чем TEMP(1:7) = X(1:7)

! Какие-то вычисления, использующие и меняющие X(1:7)

X(1:8) = TEMP(1:8)


next up previous contents
След.: Оператор SYNC IMAGES Выше: Операторы синхронизации Пред.: Операторы синхронизации   Содержание
Ilya A. Chernov 2012-12-19
X