Память в Win32.Директива #pragma data_seg().(c) И.В. Радинский, 06.10.1999 г.
Как-то раз, передо мной встала проблема - у меня была куча EXE- и DLL-файлов, входящих в одну большую систему. Как водится в больших системах, у нее были одни глобальные настройки и объекты, которые использовали те или иные модули одновременно. Настройки - это не проблема ведь можно просто хранить их в одном файле, который читают все модули. Проблема в объектах - я захотел создать группу разделяемых объектов по работе с БД, и чтобы все модули видели их, ну и заодно можно было бы хранить и общие настройки. Я хотел это реализовать в одной DLL, которую загружали бы модули, и получали бы, таким образом, доступ к этим общим данным. Проблема нетривиальная - ведь в Win32 каждый процесс имеет свое собственное адресное пространство в 4 Гб, и это все, что он "видит". Если процесс загружает DLL, то ее код проецируется в его адресное пространство и она (DLL) при этом теряет почти всю свою индивидуальность: для потоков код и данные DLL - просто дополнительный код и данные, оказавшиеся в адресном пространстве процесса. Когда поток вызывает из DLL какую-то функцию, та считывает свои параметры из стека потока и размещает в этом стеке собственные локальные переменные. Кроме того, любые созданные кодом DLL объекты принадлежат вызывающему потоку или процессу - DLL в Win32 ничем не владеет. Но. Есть одно "но". Переменные в EXE- или DLL-файлах можно поместить в особые раделы, которые можно разделить для всех процессов. Немного о разделах. Начнем с того, что любой образ EXE- или DLL-файла состоит из группы разделов (sections). Вот названия наиболее часто встречающихся разделов:
Попробуйте посмотреть любой EXE- или DLL-файл - и вы наверняка найдете несколько разделов из этой таблицы. Так вот, например, этот код: #pragma data_seg("MySection") заставит компилятор создать раздел MySection и поместить в него все ИНИЦИАЛИЗИРОВАННЫЕ переменные, встретившиеся между #pragma data_seg("MySection") и #pragama data_seg(). Директива #pragma comment(linker, "/SECTION:MySection, RWS") говорит компановщику включить строку сделать раздел MySection с аттрибутами READ, WRITE и SHARED. Угадайте с трех раз, какие переменные попадут в эту раздел. Вот они - грабли !!! Только szName и попадет ! А lModuleUsage попадает в секцию .bss (неинициализированные данные) - т.е. каждый поток будет иметь свою собственную lModuleUsage ! Отсюда сразу выходит, что код типа #pragma data_seg("MySection") обречен - переменная g_Session будет в разделе .bss, а никак не в MySection. Если подумать, то это справедливо - ведь каждый процесс вызывает конструктор объекта. А где исполняется конструктор - правильно, в адресном пространстве процесса. И все побочные данные объекта где будут? В адресном пространстве этого самого процесс а, что для других процессов уже никак не подходит. А от такой схемы пришлось отказаться. Во-первых таким образом нарушается зашита уровня B (B-level security). Во-вторых ошибки в приложении с общими переменными могу повлиять на другие приложения, т.е. одна программа может "завалить" всю систему. |
|
|
|