Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаба10.doc
Скачиваний:
11
Добавлен:
12.11.2019
Размер:
196 Кб
Скачать
☆

2.1. Статические данные разделяются несколькими экземплярами exe или dll

Когда создается новый процесс для уже выполняемого приложения, система просто открывает другое проецируемое в память представление (view) объекта «проекция файла» (file-mapping object), идентифицирующего образ исполняемого файла, и создает новые объекты «процесс» и «поток» (для первичного потока). Этим объектам присваиваются идентификаторы процесса и потока. С помощью проецируемых в память файлов несколько одновременно выполняемых экземпляров приложения может совместно использовать один и тот же код, загруженный в оперативную память. Здесь возникает небольшая проблема. Процессы используют линейное (flat) адресное пространство. При компиляции и компоновке программы весь ее код и данные объединяются в нечто, так сказать, большое и цельное. Данные, конечно, отделены от кода, но только в том смысле, что они расположены вслед за кодом в ЕХЕ-файле. На самом деле содержимое файла разбито на отдельные разделы (sections). Код находится в одном разделе, а глобальные переменные — в другом. Разделы выравниваются по границам страниц. Приложение определяет размер страницы через функцию GetSystemInfo. В EXE- или DLL-файле раздел кода обычно предшествует разделу данных.

Вот упрощенная иллюстрация того, как код и данные приложения загружаются в виртуальную память, а затем отображаются на адресное пространство процесса:

Рисунок 2.1. Адресное пространство одного экземпляра программы

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

Рисунок 2.2. Адресное пространство двух экземпляров программы

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

Рисунок 2.1. Адресное пространство двух экземпляров программы при изменении глобальных данных одним из экземпляров программы

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

Аналогичная цепочка событий происходит и при отладке приложения. Например, запустив несколько экземпляров программы, необходимо отладить только один из них. Вызвав отладчик, ставится в строке исходного кода точку прерывания. Отладчик модифицирует код, заменяя одну из команд на языке ассемблера другой — заставляющей активизировать сам отладчик. После модификации кода все экземпляры программы, доходя до исполнения измененной команды, приводили бы к его активизации. Чтобы этого избежать, система вновь использует копирование при записи. Обнаружив попытку отладчика изменить код, она выделяет новый блок памяти, копирует туда нужную страницу и позволяет отладчику модифицировать код на этой копии.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]