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

2.2. Использование общего раздела в приложениях для межпроцессного взаимодействия

По умолчанию для большей безопасности глобальные и статические данные не разделяются несколькими проекциями одного и того же EXE или DLL. Но иногда удобнее, чтобы несколько проекций EXE разделяли единственный экземпляр переменной. Например, в Windows не так-то просто определить, запущено ли несколько экземпляров приложения. Если бы была переменная, доступная всем экземплярам приложения, она могла бы отражать число этих экземпляров. Тогда при запуске нового экземпляра приложения его поток просто проверил бы значение глобальной переменной (обновленное другим экземпляром приложения) и, будь оно больше 1, сообщил бы пользователю, что запустить можно лишь один экземпляр; после чего эта копия приложения была бы завершена.

Любой образ EXE- или DLL-файла состоит из группы разделов. По соглашению имя каждого стандартного раздела начинается с точки. Например, при компиляции программы весь код помещается в раздел .text, неинициализированные данные - в раздел .bss, а инициализированные — в раздел .data.

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

Таблица 2.1. Атрибуты разделов

Атрибут

Описание

READ

Разрешает чтение из раздела

WRITE

Разрешает запись в раздел

EXECUTE

Содержимое раздела можно исполнять

SHARED

Раздел доступен нескольким экземплярам приложения (этот атрибут отключает механизм копирования при записи)

Некоторые из часто встречающихся разделов перечислены в таблице ниже:

Таблица 2.2. Типы разделов

Имя раздела

Описание

bss

Неинициализированные данные

CRT

Неизменяемые данные библиотеки С

data

Инициализированные данные

.debug

Отладочная информация

.didat

Таблица имен для отложенного импорта (delay imported names table)

edata

Таблица экспортируемых имен

idata

Таблица импортируемых имен

.rdata

Неизменяемые данные периода выполнения

.reloc

Настроечная информация — таблица переадресации (relocation table)

.rsrc

Ресурсы

.text

Код ЕХЕ или DLL

.tls

Локальная память потока

.xdata

Таблица для обработки исключений

Кроме стандартных разделов, генерируемых компилятором и компоновщиком, можно создавать свои разделы в EXE- или DLL-файле, используя директиву компилятора:

#pragma data_seg("имя_раздела")

Например, можно создать раздел Shared, в котором содержится единственная переменная типа LONG:

#pragma data_seg("Shared") LONG g_lInstanceCount = 0; #pragma data_seg()

Обрабатывая этот код, компилятор создаст раздел Shared и поместит в него все инициализированные переменные, встретившиеся после директивы #pragma. В приведенном примере в этом разделе находится переменная g_lInstanceCount.. Директива #pragma data_seg() сообщает компилятору, что следующие за ней переменные нужно вновь помещать в стандартный раздел данных, а не в Shared. Важно помнить, что компилятор помещает в новый раздел только инициализированные переменные. Если из предыдущего фрагмента кода исключить инициализацию переменной, она будет включена в другой раздел:

#pragma data_seg("Shared")

LONG g_lInslanceCount; #pragma data_seg()

Однако в компиляторе Microsoft Visual C++ 6.0 предусмотрен спецификатор allocate, который позволяет помещать неинициализированные данные в любой раздел. Взгляните на этот код:

// создаем раздел Shared и заставляем компилятор // поместить в него инициализированные данные #pragma data_seg("Shared")

// инициализированная переменная, по умолчанию помещается в раздел Shared int а = 0;

// неинициализированная переменная, по умолчанию помещается в другой раздел int b;

// сообщаем компилятору прекратить включение инициализированных данных // в раздел Shared #pragma data_seg()

// инициализированная переменная, принудительно помещается в раздел Shared __declspec(allocate("Shared")) int с = 0;

// неинициализированная переменная, принудительно помещается в раздел Shared __declspec(allocate("Shared")) int d;

// инициализированная переменная, по умолчанию помещается в другой раздел int e = 0;

// неинициализированная переменная, по умолчанию помещается в другой раздел int f;

Чтобы спецификатор allocate работал корректно, сначала должен быть создан соответствующий раздел. Так что, ели убрать из предыдущего фрагмента кода первую строку #pragma data_seg, пример не будет компилироваться.

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

Чтобы переменные стали разделяемыми, одного указания компилятору выделить их в какой-то раздел мало. Надо также сообщить компоновщику, что переменные в этом разделе должны быть общими. Для этого предназначен ключ /SECTION компоновщика

/SECTION:имя, атрибуты

За двоеточием укажите имя раздела, атрибуты которого необходимо изменить. В примере нужно изменить атрибуты раздела Shared, поэтому ключ должен выглядеть так:

/SECTION:Shared, RWS

После запятой задаются требуемые атрибуты. При этом используются такие сокращения R (READ), W (WRITE), E (EXECUTE) и S(SHARED). В данном случае указано, что раздел Shared должен быть «читаемым», «записываемым» и «разделяемым». Если необходимо изменить атрибуты более чем у одного раздела, указывайте ключ /SECTION для каждого такого раздела.

Соответствующие директивы для компоновщика можно вставлять прямо в исходный код:

#pragma comment(linker, /SECTION Shared, RWS )

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

Пример объявления разделяемой переменной:

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

#pragma data_seg("Shared") volatile LONG g_lApplicationInstances = 0; #pragma data_seg()

// указываем компоновщику, что раздел Shared должен быть // читаемым, записываемым и разделяемым #pragma comment(linker, "/Section.Shared,RWS")

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