Джонсон Харт - Системное программирование в среде Windows
hNode = HeapCreate(HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, NODE_HEAP_ISIZE, 0);
hData = HeapCreate(HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, DATA_HEAP_ISIZE, 0);
/* Обработать входной файл, создавая дерево. */
pRoot = FillTree(hIn, hNode, hData);
/* Отобразить дерево в порядке следования ключей. */
_tprintf(_T("Сортируемый файл: %sn"), argv [iFile]);
Scan(pRoot);
} _ finally { /* Кучи и дескрипторы файлов всегда закрываются.
/* Уничтожить обе кучи и структуры данных. */
if (hNode !=NULL) HeapDestroy (hNode);
if (hNode != NULL) HeapDestroy (hData);
hNode = NULL;
hData = NULL;
if (hIn != INVALID_HANDLE_VALUE) CloseHandle (hIn);
}
} /* Конец основного цикла обработки файлов и try-блока. */
__except(EXCEPTION_EXECUTE_HANDLER) {
_stprintf(ErrorMessage, _T("n%s %s"), _T("sortBT, ошибка при обработке файла:"), argv [iFile]);
ReportError(ErrorMessage, 0, TRUE);
}
return 0;
}
В программе 5.2 представлены функции, которые фактически реализуют алгоритмы поиска с использованием бинарного дерева. Первая из этих функций, FillTree, распределяет память в обеих кучах. Вторая функция, KeyCompare, используется также в нескольких других программах в данной главе. Заметьте, что функции FillTree и KeyCompare используют обработчики завершения и исключений программы 5.1, которая вызывает эти функции. Таким образом, ошибки распределения памяти будут обрабатываться основной программой, которая после этого продолжит свое выполнение, переходя к обработке следующего файла.
Программа 5.2. FillTree и другие функции управления деревом поискаLPTNODE FillTree(HANDLE hIn, HANDLE hNode, HANDLE hData)
/* Заполнение дерева записями из входного файла. Используется обработчик исключений вызывающей программы. */
{
LPTNODE pRoot = NULL, pNode;
DWORD nRead, i;
BOOL AtCR;
TCHAR DataHold [MAX_DATA_LEN] ;
LPTSTR pString;
while (TRUE) {
/* Разместить и инициализировать новый узел дерева. */
pNode = HeapAlloc(hNode, HEAP_ZERO_MEMORY, NODE_SIZE);
/* Считать ключ из следующей записи файла. */
if (!ReadFile(hIn, pNode->Key, TKEY_SIZE, &nRead, NULL) || nRead != TKEY_SIZE) return pRoot;
AtCR = FALSE; /* Считать данные до конца строки. */
for (i = 0; i < MAX_DATA_LEN; i++) {
ReadFile(hIn, &DataHold [i], TSIZE, &nRead, NULL);
if (AtCR && DataHold [i] == LF) break;
AtCR = (DataHold [i] == CR);
}
DataHold[i – 1] = ' ';
/* Объединить ключ и данные — вставить в дерево. */
pString = HeapAlloc(hData, HEAP_ZERO_MEMORY, (SIZE_T)(KEY_SIZE + _tcslen (DataHold) + 1) * TSIZE);
memcpy(pString, pNode->Key, TKEY_SIZE);
pString [KEY_SIZE] = ' ';
_tcscat (pString, DataHold);
pNode->pData = pString;
InsertTree(&pRoot, pNode);
} /* Конец цикла while (TRUE). */
return NULL; /* Ошибка */
}
BOOL InsertTree(LPPTNODE ppRoot, LPTNODE pNode)
/* Добавить в дерево одиночный узел, содержащий данные. */
{
if (*ppRoot == NULL) {
*ppRoot = pNode;
return TRUE;
}
/* Обратите внимание на рекурсивные вызовы InsertTree. */
if (KeyCompare(pNode->Key, (*ppRoot)->Key) < 0) InsertTree(&((*ppRoot)->Left), pNode);
else InsertTree(&((*ppRoot)->Right), pNode);
}
static int KeyCompare(LPCTSTR pKey1, LPCTSTR pKey2)
/* Сравнить две записи, состоящие из обобщенных символов. */
{
return _tcsncmp(pKey1, pKey2, KEY_SIZE);
}
static BOOL Scan(LPTNODE pNode)
/* Рекурсивный просмотр и отображение содержимого бинарного дерева. */
{
if (pNode == NULL) return TRUE;
Scan(pNode->Left);
_tprintf(_T ("%sn"), pNode->pData);
Scan(pNode->Right);
return TRUE;
}
Примечание
Очевидно, что данную реализацию дерева поиска нельзя назвать самой эффективной, поскольку дереву поиска ничто не мешает стать несбалансированным. Разумеется, о балансировке дерева поиска следовало бы позаботиться, однако на организацию управления памятью в программе это никак не повлияет.
Отображение файлов
Динамическая память, распределенная в кучах, должна физически размещаться в файле подкачки. Управление перемещением страниц между физической памятью и файлом подкачки, а также отображением файла подкачки на виртуальное адресное пространство процесса осуществляется средствами ОС, ответственными за управление памятью. По завершении выполнения процесса физическое пространство в этом файле освобождается.
Те же функциональные возможности Windows, которые обеспечивают отображение файла подкачки, позволяют отображать и обычные файлы. Отображение файлов дает следующие преимущества:
• Отпадает необходимость в выполнении операций непосредственного файлового ввода/вывода (чтения и записи).
• Структуры данных, созданные в памяти, будут сохраняться в файле для последующего использования этой же или другими программами. Необходимо тщательно следить за правильностью использования указателей, что иллюстрируется в программе 5.5.
• Становится возможным применение удобных и эффективных алгоритмов, ориентированных на работу с файлами "в памяти" (in-memory files) (сортировка, деревья поиска, обработка строк и тому подобное), которые позволяют обрабатывать хранящиеся в файлах данные даже в тех случаях, когда размеры файлов значительно превышают доступный объем физической памяти. При больших размерах файлов особенности организации страничного обмена могут оказывать заметное влияние на производительность.
• В некоторых случаях значительно повышается эффективность обработки файлов.
• Исчезает необходимость в управлении буферами и манипулировании содержащимися в них данными файлов. Всю эту тяжелую работу выполняет ОС, причем делает она это в высшей степени эффективно и надежно.
• Обеспечивается возможность разделения памяти несколькими параллельно выполняющимися процессами (глава 6) за счет отображения на их виртуальные адресные пространства одного и того же обычного файла или файла подкачки (разделение памяти несколькими процессами является одной из основных причин использования объекта отображения файла подкачки).
• Отпадает необходимость в расходовании излишнего пространства файла подкачки.
ОС сама использует методы отображения файлов для реализации DLL, а также для загрузки и выполнения исполняемых (.EXE) файлов. Библиотеки DLL описаны в конце настоящей главы.
Объекты отображения файлов
Сначала необходимо создать для открытого файла объект отображения файла (file mapping object), у которого имеется дескриптор, а затем отобразить этот файл или только некоторую его часть на виртуальное адресное пространство процесса. Объектам отображения можно присваивать имена, по которым к ним смогут обращаться другие процессы, разделяющие память совместно с данным процессом. Кроме того, объекты отображения файлов имеют параметры размера и атрибуты защиты.
HANDLE CreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpsa, DWORD dwProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpMapName)
Возвращаемое значение: в случае успешного выполнения — дескриптор объекта отображения файла, иначе — NULL.
ПараметрыhFile — дескриптор открытого файла, атрибуты защиты которого совместимы с флагами защиты, указанными параметром dwProtect. Значение этого дескриптора (тип данных HANDLE), равное 0xFFFFFFFF (его эквивалент — символическая константа INVALID_HANDLE_VALUE), соответствует системному файлу подкачки, и его можно использовать для организации разделения памяти несколькими процессами без создания отдельного файла.
LPSECURITY_ATTRIBUTES — позволяет указать атрибуты защиты объекта отображения.
dwProtect — с помощью флагов, которые приводятся ниже, определяет возможности доступа к представлению файла при его отображении. Помимо упомянутых флагов предусмотрены дополнительные флаги, имеющие специальное назначение. Так, флаг SEC_IMAGE указывает на то, что открытый файл, на основе которого создается объект отображения, является исполняемым загрузочным модулем; для получения более подробной информации обратитесь к оперативной справочной документации.
• PAGE_READONLY: страницы в указанной области отображения доступны программе только для чтения; программа не может осуществлять в них запись или запускать на выполнение. Файл с дескриптором hFile должен быть открыт с правами доступа GENERIC_READ.
• PAGE_READWRITE: предоставляет полный доступ к объекту, если файл с дескриптором hFile был открыт с правами доступа GENERIC_READ и GENERIC_WRITE.
• PAGE_WRITECOPY: при изменении отображения файла его приватная (для данного процесса) копия записывается в файл подкачки, а не в исходный файл. Отладчики могут использовать этот флаг для установки точек прерывания в разделяемом коде.
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Джонсон Харт - Системное программирование в среде Windows, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


