АТОМЫ
Еслиабстрагироваться от вопросов синхронизации, то обмен данными между потокамиодного процесса не представляет никакой сложности — имея общее адресноепространство и общие открытые файлы, потоки получают беспрепятственный доступ кданным друг друга.
Другое дело —обмен данными потоков, выполняющихся в рамках разных процессов.
Для защитыпроцессов друг от друга ОС возводит мощные изолирующие преграды, которые нетолько защищают процессы, но и не позволяют им передавать друг другу данные.
Потоки разныхпроцессов работают в разных адресных пространствах. Однако операционная системаимеет доступ ко всем областям памяти, поэтому она может играть роль посредникав информационном обмене прикладных потоков.
Привозникновении необходимости в обмене данными поток обращается с запросом к ОС.По этому запросу ОС, пользуясь своими привилегиями, создает различные системныесредства связи, такие, например, как каналы или очереди сообщений.
Эти средства,так же как и рассмотренные выше средства синхронизации процессов, относятся кклассу средств межпроцессного взаимодействия, то есть IPC (Inter Process Communications).
Тот факт, чтомеханизмы IPC работают на уровне операционной системы, положительно сказываетсяна скорости и надежности программ и программных комплексов, построенных с ихиспользованием. Эффективность приложений соответственно возрастает.
Такимобразом, IPC становится необходим в том случае, если поток одного процессадолжен передать данные потоку другого процесса.
ИнтерфейсWin32 API предоставляет приложениям возможность хранения строк вструктурах, известных под названием таблиц атомов.
После тогокак программа сохранит строку в таблице атомов, она может обратиться к этойстроке, используя атом.
Aтом (atom) представляет собойуникальное 16-разрядное значение, которое связано со строковой константой.
Использованиеатома в качестве ссылки на строку сродни применению дескриптора памяти дляобращения к блоку общих глобальных данных.
Подобиеимеющейся у приложения возможности передавать дескриптор памяти интерфейсуWin32 API с целью получения указателя на содержимое блока данных (с помощьюфункции GlobalLock()), приложение может также использовать средства Win32 API для получения значениястроки, связанной с атомом.
Значениестроки, которое представляет атом, известно под названием имени атома (atom name). Применение атомов:
1. Атомыприменяются в приложениях ради экономии памяти. Сохранение неоднократно встречающихсястрок в таблице атомов приложения позволяет экономить память, поскольку вданном случае значение строки сохраняется только один раз.
Прочиеэкземпляры строки занимают лишь по 2 байта памяти, которая требуется для атома,вместо целого ряда байтов, необходимых для хранения копии конкретной строки.
Еще однапричина хранения строк в виде атомов состоит в том, что таблицы атомов повышаютобщую производительность при сравнении строк, поскольку вместо сравнениякаждого байта обеих строк в данном случае сравниваются лишь 16-разрядные атомы.
2. Крометого, атомы имеют важное значение и для обмена данными между программами.
Таблицаатомов, которая является глобальной для всех процессов, называется глобальнойтаблицей атомов (global atom table) и используется для обмена данными между процессами. Применениеатомов для обмена данными между приложениями является одним из основополагающихпринципов динамического обмена данными (DDE).
3. Атомытакже широко используются для хранения строк переменной длины в дескрипторахобъектов OLE (технологии встраивания и связывания объектов).
В результатеприменения атомов в дескрипторах данных OLE получаются болеекомпактные структуры фиксированного размера с существенно более простым методомобмена.
Работа стаблицами атомов
Существуетдва вида таблиц атомов:
1. Локальные
2. Глобальные.
1. У каждогопроцесса имеется собственная таблица атомов. Значение локального атома являетсяуникальным для процесса, в котором оно определено.
С другойстороны, доступ к атомам, хранящимся в глобальной таблице атомов, можетвыполняться из любого приложения. Что касается любого конкретного глобальногоатома, то по заданному имени атома интерфейс Win32 API вернет каждому приложениюодин и тот же атом.
Функция AddAtom() сохраняет строки влокальной таблице атомов. Имена атомов сохраняются в том же регистре, в которомони вводились.
Всякий разкогда функция AddAtom() вызывается для уже существующего атома, Windows увеличивает счетчиквнутренних ссылок на этот атом.
Синтаксисфункции AddAtom() следующий
ATOM AddAtom (LPCTSTR lpszStringToStore )
Параметры:
lpszStringToStore – указатель насохраняемую строку, которая завершается нулевым символом. Максимальная длинастроки составляет 255 символов. Если первым символом строки оказывается знак #,а после него следуют цифры, представляющие целое число, меньшее константы MAXINATOM, тогда возвращаетсяцелый атом.
Возвращаемоезначение. При успешном выполнении – вновь созданный атом. Если указанная строкауже существует в таблице атомов, возвращается тот же самый атом, что и исходнаястрока; в противном случае – 0.
Дляуменьшения счетчика ссылок на атом применяется функция DeteteAtom(). Когда число ссылок достигаетнуля, атом из таблицы атомов удаляется. Синтаксис функции DeleteAtom() следующий
ATOM DeleteAtom (ATOM nAtom)
Параметры:
nAtom – атом, который удаляетсяиз локальной таблице атомов. Целые атомы не могут быть удалены, хотя значение NULL возвращается всякий раз,когда они используются в качестве аргументов функции DeleteAtom().
Возвращаемоезначение. При успешном выполнении – NULL, в противном случае – значение nAtom.
Функция FindAtom() осуществляет поиск атома,который соответствует заданной строке, в локальной таблице атомов.
Поисквыполняется без учета регистра. Синтаксис функции FindAtom() следующий
ATOM FindAtom (LPCTSTR lpszString )
Параметры:
lpszString – указатель на искомуюстроку, которая завершается нулевым символом. Если первым символом строкиоказывается знак #, а после него следуют цифры, представляющие целое число,меньшее константы MAXINATOM, тогда возвращается синтезированный целочисленный атом с темже значением.
Возвращаемоезначение. При успешном выполнении – 16-разрядное значение локального атома,связанного с указанной строкой; в противном случае – NULL.
Для возвратаимени атома из таблицы атомов применяется функция GetAtomName(). При этом имя атомавозвращается в том же регистре, в котором оно первоначально сохранялось.
2. Дляуправления, глобальными таблицами атомов имеется аналогичный набор функцийуправления атомами.
Например, функцияGlobalAddAtom() добавляет атомы вглобальную таблицу атомов подобно тому, как это делает функция AddAtom() по отношению к локальнойтаблицы атомов.
К другимфункциям управления глобальными таблицами атомов относятся GlobalDeleteAtom(), GlobalFindAtom() и GlobalGetAtomName().
И последняяфункция управления атомами InitAtomTable() устанавливает количество элементов верхнегоуровня в локальной таблице атомов в соответствие с заданным значением.
По умолчаниюколичество элементов верхнего уровня как в локальной, так и в глобальнойтаблице атомов равно 37.
Это отнюдь неозначает, что в таблице можно разместить только 37 атомов, а скорее отражаеттот факт, что вероятность конфликта, а значит, и замедления поиска в таблице,оказывается больше при наличии в таблице 37 элементов, чем, скажем, 80элементов.
Прежде чемдобавлять атомы в локальную таблицу атомов, необходимо сначала вызвать функцию InitAtomTable. Кроме того, значение, передаваемойэтой функции, всегда должно быть простым числом.
Если простоечисло не используется, тогда вероятность конфликтов возрастет, а значит и замедлитсяпоиск в таблице. Синтаксис функции FindAtom() следующий
BOOL InitAtomTable (DWORD nSize)
Параметры:
nSize – количество элементовверхнего уровня, устанавливаемых в локальной таблице атомов.
Возвращаемоезначение. При успешном выполнении – TRUE, в противном случае – FALSE.
Соответствующаяфункция для установки числа элементов верхнего уровня в глобальных атомныхтаблицах отсутствует.Применениеглобальных атомов для обмена данными
Несмотря нато что глобальные атомы применяются исключительно для DDE, тем не менее, атомыможно без труда использовать и для обмена строковыми данными между отдельнымиэкземплярами конкретного приложения.
Для этогоотправитель вводит строку в глобальную таблицу атомов с помощью функции GlobalAddAtom(), a затем устанавливаетпараметр сообщения в соответствие со значением атома.
Получательприменяет функцию GtobalFindAtom() для получения содержимого переданных данных иудаляет соответствующий атом с помощью функции GlobalDeleteAtom().
При этомочень важно удалить атом, иначе глобальная таблица атомов окажетсяпереполненной ненужными элементами.
Например.
// Имясохраняемого атома.
LPCTSTR szAtom = «An atom.»;
LRESULTCALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch(uMsg )
{
caseWM_CREATE:
// Увеличитьдо 73 число элементов в верхней части таблицы атомов.
InitAtomTable(73 );
break;
caseWM_PAINT:
{
// Показатьрезультаты поиска атома.
static PAINTSTRUCT ps;
staticchar szWorkArea[33];
staticchar szBuffer[128];
staticATOM aAnAtom;
aAnAtom= INVALID_ATOM;
BeginPaint(hWnd, &ps );
if(aAnAtom = FindAtom( szAtom ))
{
GetAtomName(aAnAtom, szWorkArea, 32 );
wsprintf(szBuffer, «Атом не найден.»,szWorkArea );
}
else
lstrcpy( szBuffer, «Атом может бытьдобавлен.» );
TextOut(ps.hdc, 0, 0, szBuffer, lstrlen( szBuffer ) );
EndPaint(hWnd, &ps );
}
break;
caseWM_COMMAND :
switch(LOWORD( wParam ) )
{
caseIDM_ADD:
//Ввести атом.
AddAtom(szAtom );
InvalidateRect(hWnd, NULL, TRUE );
break;
case IDM_DELETE:
// Найти иудалить атом.
if( FindAtom( szAtom ) )
DeleteAtom(FindAtom( szAtom ) );
InvalidateRect(hWnd, NULL, TRUE );
break;
Целочисленныеатомы
В Windows 9.x и Windows NT/2000 поддерживаютсятакже средства сохранения строк с десятичными числами в таблицах атомов. Атомы,которые представляют собой числовые строки, называются целочисленными (целыми)атомами.
Допустимымиявляются только значения из диапазона 1-49151 (1-BFFFh).
Чтобыопределить, может ли целое значение быть размещено в таблице атомов, егоследует проверить, сравнив с константой MAXINATOM. Еще одна макрокоманда MAKEINATOM, преобразует число в целыйатом.
В листингепоказано, каким образом используются целые атомы. Следует заметить, что строка,сохраняемая в таблице атомов, на самом деле будет содержать цифры десятичногопредставления целого числа, которому предшествует знак «решетки».
Листинг. Применение целых атомов
char szStoredString[6];
WORDwValue = 1000;
ATOMaValue = AddAtom( MAKEINTATOM( wValue ) ) ;
// Значение атома равно 100.
// Строка будетсодержать число "#1000".
GetAtomName( aValue, azStoredString, 6 );
Целые атомына самом деле вообще не добавляются и не удаляются из системы.
Напротив, онисинтезируются функциями управления атомами. В приведенном примере тот же самыйрезультат может быть сохранен в строке szStoredString, если функция DeleteAtom() вообще не вызывается, приэтом вместо значения wValue подставляется значение a Value.
Такимобразом, функция DeleteAtom() может быть безболезненно вызвана и по отношению к целым атомам. Апоскольку они вообще не существуют, они и не могут быть удалены, хотя функция DeleteAtom() так или иначе возвращает0, что указывает на успешное завершение.