next up previous contents
Next: Планирование разделяемой памяти Up: DIPC - Распределенные межпроцессные Previous: Системные вызовы   Contents

Разделяемая память

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

Поэтому следует всегда помнить, что процессы будут только претендовать на разделяемую память. Они никого не ставят в известность о завершении своего доступа. Значит, нет возможности ожидать завершения использования ими разделяемой памяти для того, чтобы разрешить доступ другим процессам.

Чтобы защитить страницы разделяемой памяти от записи, нужно подвергнуть изменениям таблицы MMU. Аналогично делается и защита страниц от записи (в версиях DIPC до 2.0 желательно подгрузить страницу свопа для того, чтобы защитить ее от записи). Любой процесс, при попытке прочитать или записать защищенные от чтения страницы, столкнется со страничной ошибкой и будет приостановлен ядром. Для того чтобы страницы снова стали доступными для чтения или записи, новое содержимое передается по сети и замещает старое. С этого момента пользовательские процессы могут обращаться к нему.

DIPC может воспринимать в связке множество страниц виртуальной памяти, одновременно управляя ими всеми и передавая требующиеся. Это значит, что для любого целого n >= 1:

<размер_страницы_DIPC> =

     n * <размер_страницы_виртуальной_памяти>.

Макро dipc_page_size, включенное в файл /etc/dipc.conf, определяет размер распределенной страницы. Все компьютеры в составе кластера должны иметь одинаковый размер страниц DIPC.

Установка большего размера страницы DIPC будет означать меньшие затраты при пересылках, а также создаст возможность для компьютеров с различными исходными размерами страниц совместно работать, используя DIPC. Значение должно устанавливаться исходя из максимального размера страниц виртуальной памяти компьютеров кластера.

Писатели имеют более высокий приоритет, чем читатели. Ситуация могла бы быть обратной, но философия реализации требует обновления информации писателями в то время, когда ей пользуются только читатели. Так что, писатель будет получать доступ к разделяемой информации даже тогда, когда с ней работают другие, ``желающие быть читателями'', процессы.

Для информирования процессов о том, что они становятся писателями или читателями используются два сигнала - процессы могут выполнять любые необходимые преобразования данных в гетерогенной среде. В настоящее время при записи используется сигнал SIGURG, а при чтении - SIGPWR. В дальнейшем возможны изменения, если этим сигналам будет найдено иное применение. Они приемлемы для программ с именами DIPC_SIG_READER и DIPC_SIG_WRITER.

Все процессы на одной машине имеют одинаковый статус в отношении разделяемой памяти. Либо они все могут читать ее или записывать в нее, либо никто из них не может этого делать. Когда тип доступа машины к разделяемой памяти меняется, это затрагивает все процессы на данной машине.

Система DIPC может быть сконфигурирована для управления разделяемой памятью и ее постраничной передачей. Это так называемый режим страничной передачи. Он позволяет различным компьютерам в кластере одновременно читать или записывать различные страницы разделяемой памяти. DIPC также может воспринимать целый сегмент как неделимый блок. В этом случае можно сказать, что она оперирует в режиме посегментной передачи. Каждый участник кластера DIPC, сконфигурированный для использования собственных режимов передачи, может работать с любым другим, хотя он не всегда может получить то, что просит. Ниже показано, как два компьютера с различными режимами передачи управляют работой друг друга:

  1. И запрашивающий компьютер, и менеджер разделяемой памяти используют страницы: запрашивающий компьютер посылает запрос о странице и получает ее.
  2. Запрашивающий компьютер использует страницы, в то время как менеджер разделяемой памяти использует сегменты: запрашивающий компьютер посылает запрос менеджеру об одной странице, а менеджер высылает целый сегмент. После этого ``проситель'' может получить доступ ко всей разделяемой памяти.
  3. Запрашивающий компьютер использует сегменты, в то время как менеджер разделяемой памяти использует страницы: запрашивающий компьютер просит весь сегмент, но менеджер интерпретирует это как запрос о странице, к которой происходит действительное обращение, и посылает только ее.
  4. И запрашивающий компьютер, и менеджер разделяемой памяти используют сегменты: запрашивающий компьютер посылает запрос о целом сегменте и забирает его.
В том случае, когда DIPC сконфигурирована в режиме постраничной передачи, любая передача содержимого разделяемой памяти может охватить все сегменты. Это противоречит подходам в ряде других систем с распределенной разделяемой памятью, при которых одновременно передаются только страницы. Именно по этой причине, DIPC может быть ``основанной на сегментах'' системой с распределенной разделяемой памятью. Программы могут замедляться, особенно когда разделяемая память объемная и/или сеть ``медленная'', а пересылки частые. Это также может увеличить вычислительную нагрузку, когда программист помещает ``партию'' информации в разделяемую память и разрешает другим пользоваться целым сегментом. При этом, пиковая нагрузка будет меньше, чем при постраничном доступе.

Следствия разрешения пересылок целыми сегментами при DIPC:

  1. Упрощается работа в гетерогенной среде с различными размерами страниц.
  2. В некоторых сетях время пересылки по сети намного меньше времени подготовки к передаче - поэтому, когда передатчик готов начать действовать, последующие передачи имеют очень малое влияние на общую нагрузку.
  3. Если процессу требуется вся разделяемая память, то ее пересылка одной операцией сокращает ненужные затраты.
  4. Эта идея эксплуатируется недостаточно и заслуживает того, чтобы быть оцененной.
  5. Точное соответствие между размером страницы и программным шаблоном для доступа к разделяемой памяти, в любом случае, является маловероятным (фальшивое разделение), ибо размер страницы в разных системах различен.
При любом раскладе, пользователь может сконфигурировать DIPC на компьютере таким образом, чтобы следовать более традиционным страничным схемам.

Компьютер-владелец разделяемой памяти - это ее первостепенный писатель, которого всегда ``окружают'' читатели (если имеется хотя бы один читатель). Последовательность действий компьютера-владельца, всегда присутствующего среди читателей разделяемой памяти, примерно такая. Владелец всегда запускается как писатель, а когда возникает запрос о чтении, он конвертируется в читателя. Если процесс на другом компьютере "желает" записать данные в разделяемую память, то владелец не сможет иметь никаких прав доступа. Как только возникает запрос о чтении, менеджер разделяемой памяти размещает его перед изначальным запросом о чтении - от имени машины-владельца. В этом случае, владелец сначала становится читателем, забирающим содержимое разделяемой памяти от текущего писателя (см. ниже). Затем он предоставляет содержимое изначальному читателю (и, возможно другим ``просителям'').

Описанное поведение упрощает алгоритмы: поскольку всегда известно, как забрать содержимое разделяемой памяти, то выбирают дополнительно к существующим читателям нового. Но если надо использовать одного читателя из группы, то следует обеспечить и способы разрешения сетевых трудностей, чтобы этот пользователь не потерпел неудачи.

Короче говоря, в текущей версии DIPC лишь одна машина всегда ответственна за предоставление другим компьютерам содержимого разделяемой памяти: если это писатели, то и машина является писателем. Если присутствуют один или более читателей, то машина является владельцем. В обоих случаях, если встретилась ошибка, по большому счету ничего нельзя сделать. Если писатель не может передать содержимое, то места с обновленными данными не может быть. И если владелец терпит неудачу при выдаче запрашивающей машине данных - либо из-за ошибок сети, либо ошибок запрашивающей машины - то опять можно сделать очень немного, потому что использование отдельного читателя, возможно, завершится с тем же результатом.

Как при запросе о чтении, так и при запросе о записи, запрашивающий компьютер (если находится на связи) в конечном счете будет искать причину ошибки посредством тайм-аута и передавать SIGSEGV (сбой сегментации) всем процессам, которые имеют распределенную память, присоединенную к их адресному пространству.

Возможны следующие четыре варианта запроса машинами доступа к разделяемой памяти:

  1. Имеется читатель и отдельная машина, "желающая" читать. Поскольку владелец тоже читатель, он передает соответствующее содержимое памяти запрашивающей машине и позволяет ей продолжать работу.

    На схеме показано, как это происходит:

    Сеть (Запрашивающий компьютер) | (Компьютер-владелец) | |-1->back_end >-2-+ | <----------5----+ | | | | | | | ядро| employer--3--|->front_end --4-->shm_man |ядро | | | | | | +--6-->worker |

    Когда процесс "желает" прочесть разделяемую память, уместное содержимое которой отсутствует, возникает исключение, о чем уведомляется часть DIPC в ядре. Внутри ядра подготавливается запрос, который для ``пробуждения'' порождает back_end (1) и раздваивает employer (2); employer подключается к компьютеру-владельцу (3) и доставляет запрос о чтении соответствующего содержимого разделяемой памяти процессу shm_man (4); shm_man посылает сообщение front_end (используя ``разворачивающий'' Internet-сокет) (5); front_end раздваивает worker (6) для действительного выполнения пересылки.

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

    Сеть (Запрашивающий компьютер)|(Компьютер-владелец) | | | | | | | ядро | +-8-<front_end<---|-------7---worker | ядро | | | | | | |<-11-worker<-------------|--10--------+ +-9--<|

    Итак, worker на машине-владельце ``отдает'' разделяемую память (с помощью системного вызова shmget()) и подключается к front_end на запрашивающей машине (7), который раздваивает еще один worker (8). Затем worker на машине-владельце читает соответствующее содержимое разделяемой памяти (9) и сразу передает его (без вмешательства front_end) вновь раздвоенному worker (10), который помещает его в разделяемую память запрашивающего компьютера (11). После этого, запрашивающая машина наконец получает информацию, которую хотела.

    Ниже представлены оставшиеся действия:

    Сеть (Запрашивающий компьютер) | (Компьютер-владелец) | | worker--------12-----|------------->front_end | | | | | | ядро| front_end <----|--14--shm_man <-13-+ | | | |<-16-employer<-15-+

    После того, как worker поместил содержимое в разделяемую память, он посылает подтверждение shm_man (12 и 13). Затем shm_man посылает сигнальное сообщение оригинальному employer, который передает запрос о чтении (14 и 15); employer сообщает ядру об этом (16) и ядро перезапускает процессы, "желающие" читать разделяемую память. На этом вся операция завершается.

  2. Имеются читатель и отдельная машина, "желающая писать". Менеджер посылает защищенное от чтения сообщение всем читателям, а если нужно (новый читатель не совпадает с предыдущим), то предоставляет процессу, ``желающему быть'' писателем, соответствующее содержимое памяти, чтобы позволить ему продолжать выполнение:

    Сеть (Запрашивающий компьютер) | (Компьютер-владелец) | |-1->back_end>-2-+ | | | | | | ядро| employer--3----|->front_end--4-->shm_man|ядро | | |

    Запрос о записи попадает внутрь ядра, и back_end активируется для его обработки (1). В дальнейшем об этом информируется shm_man на машине-владельце (2, 3 и 4). Заметьте, что все сказанное может происходить на одном компьютере (если владелец хочет записывать в разделяемую память). Иногда все показанные процессы, действительно, выполняются на одной машине:

    Сеть (Компьютер-читатель) | (Компьютер-владелец) | | ядро |<-7-worker<-6-front_end<--|------------5-----shm_man | |

    Менеджер разделяемой памяти посылает защищенное от чтения сообщение всем компьютерам-читателям (среди которых может быть и машина-владелец - в этом случае используется разворачивающий адрес) (5); front_end на каждой машине раздваивает worker (6) и запрос исполняется (7). С этого момента все попытки чтения или записи соответствующего содержимого разделяемой памяти любым из этих компьютеров приведут к остановке ответственных процессов. Указанные выше действия повторяются для каждого читателя.

    Если компьютер, запрашивающий возможность записи, был одним из читателей, ему содержимое не посылается: владелец ответственен за предоставление новому ``просителю'' содержимого разделяемой памяти.

    Далее shm_man ожидает подтверждение, и когда оно прибывает, посылает сигнал employer, который изначально инициировал все процессы.

  3. Известны писатель и некто, желающий читать. Если писатель или ``проситель'' не являются владельцами, владелец возьмет на себя роль ``просителя'' о чтении разделяемой памяти. Это нужно для того, чтобы убедиться в том, что он всегда может стать читателем. После того, как все сделано, предыдущий писатель станет читателем.

    Если shm_man ``включает'' владельца, как ``желающую читать'' машину, происходит следующее:

    Сеть (Компьютер-писатель) | (Компьютер-владелец) | | ядро | worker <-6- front_end <--|------------5-----shm_man | |

    Владелец будет запрашивать у действующего компьютера - писателя о передаче ему соответствующего содержимого разделяемой памяти. Это реализуется посылкой запроса процессу front_end писателя (5), который в свою очередь разветвит worker для выполнения пересылки (6).

    Соответствующее содержимое разделяемой памяти передается компьютеру - владельцу (компьютер - владелец заменяется компьютером - писателем, а запрашивающий компьютер - владельцем).

    Когда владелец становится читателем разделяемой памяти, он обслуживает оригинальный запрос о чтении. Данная ситуация похожа на ситуацию, описанную в первом пункте.

  4. Представлены писатель и некто, желающий писать. Здесь
    shm_man передает текущему писателю защищенное от чтения сообщение и инструкцию передать соответствующее содержимое разделяемой памяти запрашивающей машине. После этого, запрашивающая машина становится новым писателем.

    Сначала shm_man уведомляется о запросе. Затем он пошлет сообщение текущему писателю защитить от записи соответствующие части разделяемой памяти и передаст содержимое новому писателю.


next up previous contents
Next: Планирование разделяемой памяти Up: DIPC - Распределенные межпроцессные Previous: Системные вызовы   Contents
2004-06-22