Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
os9 (1).doc
Скачиваний:
0
Добавлен:
20.06.2023
Размер:
190.46 Кб
Скачать

9.5.2. Общая характеристика динамического связывания

В этом случае загрузка и связывание подпрограммы происходят в момент первого обращения к ней.

Механизм реализации динамического связывания похож на реализацию оверлейной программы с учетом того, что менеджер оверлеев и таблица сегментов превращаются в средство, которое называется ДИНАМИЧЕСКИМ ЗАГРУЗЧИКОМ и которое является средством операционной системы.

Краткое описание процесса динамического связывания выглядит следующим образом.

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

Если подпрограмма загружена, то ОС сразу возвращает адрес загрузки. Если подпрограмма не загружена, то она загружается, и после этого операционная система возвращает адрес загрузки.

Пример загрузки динамической библиотеки в ОС Linux:

void *dlopen(const char *filename, int flag);

Функция dlopen() загружает динамический общий объект (общую библиотеку) из файла, имя которого указано в строке filename (завершается null) и возвращает описатель на загруженный объект.

Загрузив библиотеку, требуется найти адрес процедуры. Это делается вызовом:

void *dlsym(void *handle, char *symbol);

Функции dlsym() передаётся «описатель» динамически загруженного объекта, возвращаемого dlopen() и имя символа (с null в конце). В результате функция возвращает адрес, по которому символ расположен в памяти.

9.5.3. Механизмы динамического связывания

Представленное описание поверхностное, на самом деле все гораздо сложнее. При этом акцент делается не столько на загрузку по запросу во время выполнения, сколько на разделение процедур и данных несколькими процессами.

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

По этой причине часто разделяется единственная копия ресурса в основной памяти.

Вопросы разделения данных мы с вами подробно рассматривали в разделе “Параллельное выполнение программ”. Критические секции – это и есть решение проблемы разделения данных.

Здесь рассмотрим вопросы разделения процедур.

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

В современной практике модификация команд не является хорошим стилем. Этому существуют две причины:

  1. Логика программы становится чрезвычайно запутанной;

  2. Самоизменения не дают возможности разделять программу.

По этим причинам желательно устранить операции запоминания в пределах областей программы.

Появился термин “чистые процедуры”.

  1. Чистые процедуры не модифицируют свои собственные команды и локальные данные.

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

  3. Чистые процедуры могут разделяться более чем одним процессом.

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

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

Пример.

Пусть ARG – символическое имя ячейки, содержащей некоторую переменную. [ARG] означает содержимое ARG.

Чтобы запомнить содержимое регистра Ri в ARG, можно использовать команду:

STO Ri, ARG; [ARG] := [Ri];

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

Выходом из положения будет вариант, при котором ARG является смещением внутри собственной области любого процесса. А базовый адрес этой области хранится в регистре Rb. При переходе от процесса к процессу базовый регистр перегружается, а смещение остается неизменным.

Правильная команда будет выглядеть так:

STO Ri, ARG(Rb); [[Rb] + ARG] := [Ri];

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

Развитием использования базового регистра является понятие секции связи. Каждая разделяемая процедура содержит:

  1. код - чистую программу;

  2. секцию связи.

Схема взаимодействия процедуры с процессами через секции связи

Секция связи представляет собой таблицу со строками, соответствующими передаваемым параметрам чистой процедуры.

Чистая процедура для доступа к передаваемым параметрам работает со смещениями секции связи.

Каждый процесс формирует собственную копию секции связи и передает в нее параметры, когда обращается к процедуре.

Реально процедура будет обращаться к копии секции связи того процесса, на которую в текущий момент указывает базовый регистр. И через эту копию будет обращаться к передаваемым данным.

14

Соседние файлы в предмете Операционные системы