Традиционно распределенные вычисления базируются на модели передачи сообщений, в которой данные передаются от процессора к процессору в виде сообщений. Удаленный вызов процедур фактически является той же самой моделью (или очень близкой).
DSM - виртуальное адресное пространство, разделяемое всеми узлами (процессорами) распределенной системы. Программы получают доступ к данным в DSM примерно так же, как они работают с данными в виртуальной памяти традиционных ЭВМ. В системах с DSM данные перемещаются между локальными памятями разных компьютеров аналогично тому, как они перемещаются между оперативной и внешней памятью одного компьютера.
В модели передачи сообщений программист обеспечивает доступ к разделяемым данным посредством явных операций посылки и приема сообщений. При этом приходится квантовать алгоритм, обеспечивать своевременную смену информации в буферах, преобразовывать индексы массивов. Все это сильно усложняет программирование и отладку. DSM скрывает от программиста пересылку данных и обеспечивает ему абстракцию разделяемой памяти, к использованию которой он уже привык на мультипроцессорах. Программирование и отладка с использованием DSM гораздо проще.
В модели передачи сообщений данные перемещаются между двумя различными адресными пространствами. Это делает очень трудным передачу сложных структур данных между процессами. Более того, передача данных по ссылке и передача структур данных, содержащих указатели, является в общем случае делом сложным и дорогостоящим. DSM же позволяет передавать данные по ссылке, что упрощает разработку распределенных приложений.
Объем суммарной физической памяти всех узлов может быть огромным. Эта огромная память становится доступна приложению без издержек, связанных в традиционных системах с дисковыми обменами. Это достоинство становится все весомее в связи с тем, что скорости процессоров растут быстрее скоростей памяти и в то же время появляются очень быстрые коммуникации.
DSM-системы могут наращиваться практически беспредельно в отличие от систем с разделяемой памятью, т.е. являются масштабируемыми.
Программы, написанные для мультипроцессоров с общей памятью, могут в принципе без каких-либо изменений выполняться на DSM-системах (по крайней мере, они могут быть легко перенесены на DSM-системы).По существу, DSM-системы преодолевают архитектурные ограничения мультипроцессоров и сокращают усилия, необходимые для написания программ для распределенных систем. Обычно они реализуются программно-аппаратными средствами, но в последние годы появилось несколько коммерческих MPP с DSM, реализованной аппаратно (Convex SPP, KSR1).
При реализации DSM центральными являются следующие вопросы.
· как поддерживать информацию о расположении удаленных данных.
· как снизить при доступе к удаленным данным коммуникационные задержки и большие накладные расходы, связанные с выполнением коммуникационных протоколов.
· как сделать разделяемые данные доступными одновременно на нескольких узлах для того, чтобы повысить производительность системы.
Рассмотрим четыре основных алгоритма реализации DSM.
Все разделяемые данные поддерживает центральный сервер. Он возвращает данные клиентам по их запросам на чтение, по запросам на запись он корректирует данные и посылает клиентам в ответ квитанции. Клиенты могут использовать тайм-аут для посылки повторных запросов при отсутствии ответа сервера. Дубликаты запросов на запись могут распознаваться путем нумерации запросов. Если несколько повторных обращений к серверу остались без ответа, приложение получит отрицательный код ответа (это обеспечит клиент).
Алгоритм прост в реализации, но сервер может стать узким местом.
Чтобы избежать этого, разделяемые данные могут быть распределены между несколькими серверами. В этом случае клиент должен уметь определять, к какому серверу надо обращаться при каждом доступе к разделяемой переменной. Посылка запросов сразу всем серверам нежелательна, поскольку не снижает нагрузку на серверы. Лучшее решение - распределить данные в зависимости от их адресов и использовать функцию отображения для определения нужного сервера.
В отличие от предыдущего алгоритма, когда запрос к данным направлялся в место их расположения, в этом алгоритме меняется расположение данных - они перемещаются в то место, где потребовались. Это позволяет последовательные обращения к данным осуществлять локально. Миграционный алгоритм позволяет обращаться к одному элементу данных в любой момент времени только одному узлу. Обычно мигрирует целиком страницы или блоки данных, а не запрашиваемые единицы данных. Это позволяет воспользоваться присущей приложениям локальностью доступа к данным для снижения стоимости миграции. Однако, такой подход приводит к трэшингу, когда страницы очень часто мигрируют между узлами при малом количестве обслуживаемых запросов. Некоторые системы позволяют задать время, в течение которого страница насильно удерживается в узле для того, чтобы успеть выполнить несколько обращений к ней до миграции ее в другой узел.
Миграционный алгоритм позволяет интегрировать DSM с виртуальной памятью, обеспечивающейся операционной системой в отдельных узлах. Если размер страницы DSM совпадает с размером страницы виртуальной памяти (или кратен ей), то можно обращаться к разделяемой памяти обычными машинными командами, воспользовавшись аппаратными средствами проверки наличия в оперативной памяти требуемой страницы и замены виртуального адреса на физический. Конечно, для этого виртуальное адресное пространство процессоров должно быть достаточно, чтобы адресовать всю разделяемую память. При этом, несколько процессов в одном узле могут разделять одну и ту же страницу.
Для определения места расположения блоков данных миграционный алгоритм может использовать сервер, отслеживающий перемещения блоков, либо воспользоваться механизмом подсказок в каждом узле. Возможна и широковещательная рассылка запросов.
Предыдущий алгоритм позволял обращаться к разделяемым данным в любой момент времени только процессам в одном узле (в котором эти данные находятся). Данный алгоритм расширяет миграционный алгоритм механизмом размножения блоков данных, позволяя либо многим узлам иметь возможность одновременного доступа по чтению, либо одному узлу иметь возможность читать и писать данные (протокол многих читателей и одного писателя). Производительность повышается за счет возможности одновременного доступа по чтению, но запись требует серьезных затрат для уничтожения всех устаревших копий блока данных или их коррекции.
При использовании такого алгоритма требуется отслеживать расположение всех блоков данных и их копий. Например, каждый собственник блока может отслеживать расположение его копий. Данный алгоритм может снизить среднюю стоимость доступа по чтению тогда, когда количество чтений значительно превышает количество записей.
Этот алгоритм является расширением предыдущего алгоритма. Он позволяет многим узлам иметь одновременный доступ к разделяемым данным на чтение и запись (протокол многих читателей и многих писателей). Поскольку много узлов могут писать данные параллельно, требуется для поддержания согласованности данных контролировать доступ к ним.
Одним из способов обеспечения консистентности данных является использование специального процесса для упорядочивания модификаций памяти. Все узлы, желающие модифицировать разделяемые данные должны посылать свои модификации этому процессу. Он будет присваивать каждой модификации очередной номер и рассылать его широковещательно вместе с модификацией всем узлам, имеющим копию модифицируемого блока данных. Каждый узел будет осуществлять модификации в порядке возрастания их номеров. Разрыв в номерах полученных модификаций будет означать потерю одной или нескольких модификаций. В этом случае узел может запросить недостающие модификации.
Все перечисленные алгоритмы являются неэффективными. Добиться эффективности можно только изменив семантику обращений к памяти.
Модель консистентности представляет собой некоторый договор между программами и памятью, в котором указывается, что при соблюдении программами определенных правил работа модуля памяти будет корректной, если же требования к программе будут нарушены, то память не гарантирует правильность выполнения операций чтения/записи. В этом разделе рассматриваются основные модели консистентности используемые в системах с распределенной памятью.
Модель консистентности, удовлетворяющая условию: “Операция чтения ячейки памяти с адресом X должна возвращать значение, записанное самой последней операцией записи с адресом X”, называется моделью строгой консистентности. Указанное выше условие кажется довольно естественным и очевидным, однако оно предполагает наличие в системе понятия абсолютного времени для определения “наиболее последней операции записи”.
Все однопроцессорные системы обеспечивают строгую консистентность, но в распределенных многопроцессорных системах ситуация намного сложнее. Предположим, что переменная X расположена в памяти машины B, и процесс, который выполняется на машине A, пытается прочитать значение этой переменной в момент времени T1. Для этого машине B посылается запрос переменной X. Немного позже, в момент времени T2, процесс, выполняющийся на машине B, производит операцию записи нового значения в переменную X. Для обеспечения строгой консистентности операция чтения должна возвратить в машину А старое значение переменной вне зависимости от того, где расположена машина A и насколько близки между собой два момента времени T1 и T2. Однако, если T1-T2 равно 1 нсек, и машины расположены друг от друга на расстоянии 3-х метров, то сигнал о запросе значения переменной должен быть передан на машину B со скоростью в 10 раз превышающей скорость света, что невозможно.
P1: W(x)1 |
P1: W(x)1 |
--------------------------------> t |
-----------------------------------> t |
P2: R(x)1 |
P2: R(x)0 R(x)1 |
|
|
а) |
б) |
а) Строго консистентная память б) Память без строгой консистентности
Строгая консистентность представляет собой идеальную модель для программирования, но ее, к сожалению программистов, невозможно реализовать для распределенных систем. Однако, практический опыт показывает, что в некоторых случаях можно обходиться и более “слабыми” моделями. Все эти методы опираются на то, что должна соблюдаться последовательность определенных событий записи и чтения.
Последовательную консистентность впервые определил Lamport в 1979 г. По его определению, модель последовательной консистентности памяти должна удовлетворять следующему условию: “Результат выполнения должен быть тот-же, как если бы операторы всех процессоров выполнялись бы в некоторой последовательности, в которой операторы каждого индивидуального процессора расположены в порядке, определяемом программой этого процессора”.
Это определение означает, что при параллельном выполнении, все процессы должны “видеть” одну и ту же последовательность записей в память.
Последовательная консистентность не гарантирует, что операция чтения возвратит значение, записанное другим процессом наносекундой или даже минутой раньше, в этой модели только точно гарантируется, что все процессы знают последовательность всех записей в память. Результат повторного выполнения параллельной программы в системе с последовательной консистентностью (как, впрочем, и при строгой консистентности) может не совпадать с результатом предыдущего выполнения этой же программы, если в программе нет регулирования операций доступа к памяти с помощью механизмов синхронизации.
Два примера правильного выполнения одной программы. В примерах используются следующие обозначения:
W(x)1 - запись значения 1 в переменную x; R(x)0 - чтение значения 0 из переменной x.
P1: |
W(x)1 |
|
|
W(y)1 |
|
P2: |
|
|
W(z)1 |
|
|
P3: |
|
R(x)0 |
R(y)0 |
R(z)1 |
R(y)0 |
P4: |
|
R(x)0 |
R(y)1 |
R(z)1 |
R(x)1 |
В этом примере процессы “видят” записи в порядке W(z)1, W(x)1,W(y)1 или W(x)1, W(z)1,W(y)1.
P1: |
W(x)1 |
|
|
W(y)1 |
|
P2: |
|
|
W(z)1 |
|
|
P3: |
|
R(x)0 |
R(y)1 |
R(z)0 |
R(y)1 |
P4: |
|
R(x)1 |
R(y)1 |
R(z)0 |
R(x)1 |
В этом примере процессы “видят” записи в порядке W(x)1, W(y)1,W(z)1.Два примера неправильного выполнения той же программы.
P1: |
W(x)1 |
|
|
W(y)1 |
|
P2: |
|
|
W(z)1 |
|
|
P3: |
|
R(x)0 |
R(y)0 |
R(z)1 |
R(y)0 |
P4: |
|
R(x)0 |
R(y)1 |
R(z)0 |
R(x)1 |
Процессы Р3 и Р4 “видят” записи W(y)1 и W(z)1 в разном порядке.
P1: |
W(x)1 |
|
|
W(y)1 |
|
P2: |
|
|
W(z)1 |
|
|
P3: |
|
R(x)1 |
R(y)0 |
R(z)1 |
R(y)1 |
P4: |
|
R(x)0 |
R(y)1 |
R(z)1 |
R(x)0 |
Процесс Р4 “видит” записи W(x)1 и W(y)1 не в том порядке, как они выполнялись в процессе Р1.
Описанный выше миграционный алгоритм реализует последовательную консистентность.
Последовательная консистентность может быть реализована также следующим образом. Страницы, доступные на запись, размножаются, но операции с разделяемой памятью не должны начинаться до тех пор, пока не завершится выполнение предыдущей операции записи, выданной каким-либо процессором, т.е. будут скорректированы все копии соответствующей страницы (все записи выполняются последовательно, блокируя на время своего выполнения работу всех процессов). В системах с упорядоченным механизмом широковещания запрос на операцию модификации памяти рассылается всем владельцам копий соответствующей страницы (включая и себя). При этом, работа процессов не блокируется. Одним процессором могут быть выданы несколько запросов на модификацию данных. Любая операция чтения не должна выполняться до того как будут выполнены все выданные данным процессором запросы на модификацию (процессор получит и выполнит “свои” запросы).
Причинная модель консистентности памяти представляет собой более “слабую” модель по сравнению с последовательной моделью, поскольку в ней не всегда требуется, чтобы все процессы “видели” одну и ту же последовательность записей в память, а проводится различие между потенциально зависимыми операциями записи, и независимыми<>Рассмотрим пример. Предположим, что процесс P1 модифицировал переменную x, затем процесс P2 прочитал x и модифицировал y. В этом случае модификация x и модификация y потенциально причинно зависимы, так как новое значение y могло зависеть от прочитанного значения переменной x. С другой стороны, если два процесса одновременно изменяют значения различных переменных, то между этими событиями нет причинной связи. Операции, которые причинно не зависят друг от друга называются параллельными. независимыми<>
Причинная модель консистентности памяти определяется следующим условием: “Последовательность операций записи, которые потенциально причинно зависимы, должна наблюдаться всеми процессами системы одинаково, параллельные операции записи могут наблюдаться разными узлами в разном порядке.”
Пример.
(а) Нарушение модели причинной консистентности
P1: |
W(x)1 |
|
|
|
|
P2: |
|
R(x)1 |
W(x)2 |
|
|
P3: |
|
|
|
R(x)2 |
R(x)1 |
P4: |
|
|
|
R(x)1 |
R(x)2 |
(б) корректная последовательность для модели причинной консистентности.
P1: |
W(x)1 |
|
|
W(x)3 |
|
|
P2: |
|
R(x)1 |
W(x)2 |
|
|
|
P3: |
|
R(x)1 |
|
|
R(x)3 |
R(x)2 |
P4: |
|
R(x)1 |
|
|
R(x)2 |
R(X)3 |
При реализации причинной консистентности для случая размножения страниц выполнение операций с общей памятью требует ожидания выполнения только тех предыдущих операций записи, которые являются потенциально причинно зависимыми. Параллельные операции записи не задерживают выполнение операций с общей памятью, а также не требуют неделимости широковещательных рассылок.
Определение потенциальной причинной зависимости может осуществляться компилятором посредством анализа зависимости операторов программы по данным.
Система DSM может это осуществить посредством нумерации всех записей на каждом процессоре, распространения этих номеров по всем процессорам вместе с модифицируемыми данными, и задержке любой модификации на любом процессоре до тех пор, пока он не получит все те модификации, о которых известно процессору - автору задерживаемой модификации.
PRAM (Pipelined RAM) консистентность определяется следующим образом: “Операции записи, выполняемые одним процессором, видны всем остальным процессорам в том порядке, в каком они выполнялись, но операции записи, выполняемые разными процессорами, могут быть видны в произвольном порядке.”
Пример допустимой последовательности событий в системе с PRAM консистентностью.
P1: |
W(x)1 |
|
|
|
|
P2: |
|
R(x)1 |
W(x)2 |
|
|
P3: |
|
|
|
R(x)1 |
R(x)2 |
P4: |
|
|
|
R(x)2 |
R(x)1 |
Преимущество модели PRAM консистентности заключается в простоте ее реализации, поскольку операции записи на одном процессоре могут быть конвейеризованы: выполнение операций с общей памятью можно начинать не дожидаясь завершения предыдущих операций записи (модификации всех копий страниц, например), необходимо только быть уверенным, что все процессоры увидят эти записи в одном и том же порядке.
PRAM консистентность может приводить к результатам, противоречащим интуитивному представлению. Пример:
Процесс P1 |
Процесс P2 |
.......... |
.......... |
a = 1; |
b = 1; |
if (b==0) kill (P2); |
if (a==0) kill (P1); |
.......... |
.......... |
Оба процесса могут быть убиты, что невозможно при последовательной консистентности. Модель процессорной консистентности отличается от модели PRAM консистентности тем, что в ней дополнительно требуется когерентность памяти: “Для каждой переменной x есть общее согласие относительно порядка, в котором процессоры модифицируют эту переменную, операции записи в разные переменные - параллельны”. Таким образом, к упорядочиванию записей каждого процессора добавляется упорядочивание записей в переменные или группы
Модели PRAM консистентности и процессорной моделей с более консистентности производительнее и эффективнее строгой консистентностью, но и их ограничения для многих приложений не всегда являются необходимыми, так как требуют знание всеми процессорами порядка операций записи, выполняемых на некотором процессоре.
Рассмотрим, для примера, процесс, который в критической секции циклически читает и записывает значение некоторых переменных. Даже, если остальные процессоры и не пытаются обращаться к этим переменным до выхода первого процесса из критической секции, для удовлетворения требований описанных выше моделей консистентности они должны “видеть” все записи первого процессора в порядке их выполнения, что, естественно, совершенно не нужно. Наилучшее решение в такой ситуации - это позволить первому процессу завершить выполнение критической секции и, только после этого, переслать остальным процессам значения модифицированных переменных, не заботясь о пересылке промежуточных результатов, и порядка их вычисления внутри критической секции.
Предложенная в 1986 г. (Dubois et al.) модель слабой консистентности, основана на выделении среди переменных специальных синхронизационных переменных и описывается следующими правилами:
Доступ к синхронизационным переменным определяется моделью последовательной консистентности;
Доступ к синхронизационным переменным запрещен (задерживается), пока не выполнены все предыдущие операции записи;
Доступ к данным (запись, чтение) запрещен, пока не выполнены все предыдущие обращения к синхронизационным переменным.
Первое правило определяет, что все процессы “видят” обращения к синхронизационным переменным в определенном (одном и том же) порядке.
Второе правило гарантирует, что выполнение процессором операции обращения к синхронизационной переменной возможно только после “выталкивания” конвейера (полного завершения выполнения на всех процессорах всех предыдущих операций записи переменных, выданных данным процессором). Третье правило определяет, что при обращении к обычным (не синхронизационным) переменным на чтение или запись, все предыдущие обращения к синхронизационным переменным должны быть выполнены полностью. Выполнив синхронизацию перед обращением к общей переменной, процесс может быть уверен, что получит правильное значение этой переменной.
a) Пример допустимой последовательности событий.
P1: |
W(x)1 |
W(x)2 |
S |
|
|
|
P2: |
|
|
|
R(x)1 |
R(x)2 |
S |
P3: |
|
|
|
R(x)2 |
R(x)1 |
S |
б) Пример недопустимой последовательности событий.
P1: |
W(x)1 |
W(x)2 |
S |
|
|
P2: |
|
|
|
S |
R(x)1 |
В отличие от предыдущих моделей консистентности, модель слабой консистентности ориентирована на консистентность групповых операций чтения/записи. Эта модель наиболее эффективна для приложений, в которых отдельные (изолированные) обращения к общим переменным встречаются довольно редко.
В системе со слабой консистентностью возникает проблема при обращении к синхронизационной переменной: система не имеет информации о цели этого обращения - или процесс завершил модификацию общей переменной, или готовится прочитать значение общей переменной. Для более эффективной реализации модели консистентности система должна различать две ситуации: вход в критическую секцию и выход из нее.
В модели консистентности по выходу введены специальные функции обращения к синхронизационным переменным:
(1) ACQUIRE - захват синхронизационной переменной, информирует систему о входе в критическую секцию;
(2) RELEASE - освобождение синхронизационной переменной, определяет завершение критической секции.
Захват и освобождение используется для организации доступа не ко всем общим переменным, а только к тем, которые защищаются данной синхронизационной переменной. Такие общие переменные называют защищенными переменными.
Пример допустимой последовательности событий для модели с консистентностью по выходу. (Acq(L) - захват синхронизационной переменной L; Rel(L) - освобождение синхронизационной переменной).
P1: |
Acq(L) |
W(x)1 |
W(x)2 |
Rel(L) |
|
|
|
|
P2: |
|
|
|
|
Acq(L) |
R(x)2 |
Rel(L) |
|
P3: |
|
|
|
|
|
|
|
R(x)1 |
Следующие правила определяют требования к модели консистентности по выходу:
· До выполнения обращения к общей переменной, должны быть полностью выполнены все предыдущие захваты синхронизационных переменных данным процессором.
· Перед освобождением синхронизационной переменной должны быть закончены все операции чтения/записи, выполнявшиеся процессором прежде.
· Реализация операций захвата и освобождения синхронизационной переменной должны удовлетворять требованиям процессорной консистентности (последовательная консистентность не требуется).
При выполнении всех этих требований и использовании методов захвата и освобождения, результат выполнения программы будет таким же, как при выполнении этой программы в системе с последовательной моделью консистентности.
Существует модификация консистентности по выходу - “ленивая”. В отличие от описанной (“энергичной”) консистентности по выходу, она не требует выталкивания всех модифицированных данных при выходе из критической секции. Вместо этого, при запросе входа в критическую секцию процессу передаются текущие значения защищенных разделяемых данных (например, от процесса, который последним находился в критической секции, охраняемой этой синхронизационной переменной). При повторных входах в критическую секцию того же самого процесса не требуется никаких обменов сообщениями.
Эта консистентность представляет собой еще один пример модели консистентности, которая ориентирована на использование критических секций. Также, как и в предыдущей модели, эта модель консистентности требует от программистов (или компиляторов) использование механизма захвата/освобождения для выполнения критических секций. Однако, в этой модели требуется, чтобы каждая общая переменная была связана с некоторой синхронизационной переменной (типа семафора или события), при этом, если доступ к элементам массива, или различным отдельным переменным, может производиться независимо (параллельно), то эти элементы массива (общие переменные) должны быть связаны с разными синхронизационными переменными. Таким образом, вводится связь между синхронизационными переменными и общими переменными, которые они охраняют.
Кроме того, критические секции, охраняемые одной синхронизационной переменной могут быть двух типов:
· секция с монопольным доступом (для модификации переменных);
· секция с немонопольным доступом (для чтения переменных).
Рассмотрим использование синхронизационных переменных.
Каждая синхронизационная переменная имеет временного владельца - последний процесс, захвативший доступ к этой переменной. Этот владелец может в цикле выполнять критическую секцию не посылая при этом сообщений другим процессорам. Процесс, который в данный момент не является владельцем синхронизационной переменной, но требующий ее захвата, должен послать запрос текущему владельцу этой переменной для получения значения этой переменной и права собственности на синхронизационную переменную. Разрешена ситуация, когда синхронизационная переменная имеет несколько владельцев, но только в том случае, если связанные с этой переменной общие данные используются только для чтения.
Ниже приведены формальные правила, определяющие модель консистентности по входу:
Процесс не может захватить синхронизационную переменную до того, пока не обновлены все переменные этого процесса, охраняемые захватываемой синхронизационной переменной;
Процесс не может захватить синхронизационную переменную в монопольном режиме (для модификации охраняемых данных), пока другой процесс, владеющий этой переменной (даже в немонопольном режиме), не освободит ее;
Если какой-то процесс захватил синхронизационную переменную в монопольном режиме, то ни один процесс не сможет ее захватить даже в немонопольном режиме до тех пор, пока первый процесс не освободит эту переменную и будут обновлены текущие значения охраняемых переменных в процессе, запрашивающем синхронизационную переменную.
Различия между описанными моделями консистентности памяти определяются ограничениями моделей, простотой реализации и способами программирования. В приведенной ниже таблице определены отличительные характеристики описанных моделей консистентности памяти.
(а) Модели консистентности, не использующие операции синхронизации.
Консистентность |
Описание |
Строгая |
Упорядочение всех доступов к разделяемым данным по абсолютному времени |
Последовательная |
Все процессы видят все записи разделяемых данных в одном и том же порядке |
Причинная |
Все процессы видят все причинно-связанные записи данных в одном и том же порядке |
Процессорная |
PRAM-консистентность + когерентность памяти |
PRAM |
Все процессоры видят записи любого процессора в одном и том же порядке |
(б) Модели консистентности с операциями синхронизации.
Консистентность |
Описание |
Слабая |
Разделяемые данные можно считать консистентными только после выполнения синхронизации |
По выходу |
Разделяемые данные становятся консистентными после выхода из критической секции |
По входу |
Связанные с критической секцией разделяемые данные становятся консистентными при входе в нее |
Общая память разбивается на порции одинаковой длины - страницы или блоки. Если выбрать длину совпадающей (или кратной) длине страницы оперативной памяти процессоров (если их память страничная), то можно будет воспользоваться механизмом защиты памяти для обнаружения отсутствующих страниц DSM и аппаратным механизмом замены виртуального адреса на физический.
К этому же типу DSM (не знающих заранее ничего о содержимом памяти) можно отнести и аппаратные реализации на базе кэшей (Convex SPP).
В DSM системах с разделяемыми переменными только отдельные структуры данных разделяются между процессорами. Программист должен точно определить какие переменные в программе должны разделяться, а какие не должны.
Знание информации о режиме использования разделяемых переменных позволяет воспользоваться более эффективными протоколами когерентности.
Рассмотрим следующую программу, которая автоматически распараллеливается посредством размножения всех переменных на все процессоры и распределения между ними витков цикла.
s = 0; zer = 0; for (i = 1; i < L2-1; i++) { r =
A[i-1]*A[i+1]; C[i] = r; s = s + r*r;
if (A[i]==0) { izer = i}; }
A[izer] = 1;
Переменные внутри цикла используются в следующих режимах:
А - только на чтение;
r - приватно (фактически не является разделяемой);
C - раздельно используется (любой элемент массива изменяется не более, чем одним процессом, и никакой процесс не читает элемент, изменяемый другими);
s - редукционная переменная, используемая для суммирования;
izer - переменная, хранящая индекс последнего нулевого элемента массива А;
Приведения в консистентное состояние переменных A и r - не требуется.
Для приведения в консистентное состояние массива С необходимо при завершении цикла каждому процессу послать остальным все свои изменения в массиве С.
Для переменной s в конце цикла надо довыполнить операцию редукции - сложить все частичные суммы, полученные разными процессорами в своих копиях переменной s и разослать результат всем процессорам (если бы начальное значение переменной s было отлично от нуля, то это надо было бы учесть).
Переменной izer на всех процессорах при выходе из цикла должно быть присвоено то значение, которое было получено на витке цикла с максимальным номером (требуется фиксировать на каждом процессоре максимальный номер витка, на котором переменной присваивается значение. При распределении витков последовательными блоками между процессорами достаточно фиксировать сам факт изменения переменной каждым процессором).
Вне цикла приведение в консистентное состояние переменной A[izer] не требуется, поскольку на каждом процессоре выполняется один и тот же оператор, который присваивает одно и то же значение всем копиям переменной.
Последнюю группу образуют многопроцессорные системы с объектной организацией распределенной общей памятью. В отличие от всех остальных рассмотренных систем, программы для объектно-ориентированной DSM системы не могут напрямую использовать общие переменные, а только через специальные функции-методы. Система поддержки выполнения параллельных программ, получив запрос на использование некоторой общей переменной, обрабатывает его, поддерживая при этом консистентное состояние разделяемых данных. Весь контроль осуществляется только программными средствами.В тех случаях, когда для балансировки загрузки процессоров применяется миграция данных, воспользоваться соседством расположения данных в локальной памяти процессора затруднительно.
В таких случаях потери эффективности из-за доступа к данным через функции могут быть вполне приемлемыми, поскольку они могут сполна компенсироваться тем выигрышем, который достигается балансировкой загрузки.