Прогон программы, демонстрирующей передачу информации от одного процесса к другому через разделяемую память
Рассмотрим текст двух программ first.c и second.c
First.c
#include <windows.h>
#include <stdio.h>
void main(void){
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt", // имя файла
GENERIC_READ | GENERIC_WRITE, // файл для чтения и записи
FILE_SHARE_READ| FILE_SHARE_WRITE,// режим совместного доступа
NULL, // защита по умолчанию
OPEN_EXISTING, // файл должен существовать
FILE_ATTRIBUTE_NORMAL, // атрибуты файла
NULL); // файл атрибутов
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file\n");
hMapFile = CreateFileMapping(hFile, // описатель отображаемого файла
NULL, // атрибуты защиты по умолчанию
PAGE_READWRITE, // режим доступа
0, // старшее двойное слово размера буфера
0, // младшее двойное слово размера буфера
"MyFileObject"); // имя объекта
if (hMapFile == NULL) printf("Could not create file-mapping object.\n");
lpMapAddress = MapViewOfFile(hMapFile, // описатель отображаемого файла
FILE_MAP_ALL_ACCESS, // режимы доступа
0, 0, // отображение файла с начала
0); // отображение целого файла
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
sprintf(String, "Hello, world");
getchar();
}
Пример 10.1. (html, txt)
Second.c
#include <windows.h>
#include <stdio.h>
void main(void){
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt", // имя файла
GENERIC_READ | GENERIC_WRITE, // файл для чтения и записи
FILE_SHARE_READ| FILE_SHARE_WRITE,// режим совместного доступа
NULL, // защита по умолчанию
OPEN_EXISTING, // файл должен существовать
FILE_ATTRIBUTE_NORMAL, // атрибуты файла
NULL); // файл атрибутов
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open file\n"); // process error
}
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, // разрешение чтения-записи
FALSE, // описатель не наследуется
"MyFileObject"); // имя объекта проецируемого файла
if (hMapFile == NULL) printf("Could not open Filemapping\n");
lpMapAddress = MapViewOfFile(hMapFile, // описатель отображаемого файла
FILE_MAP_ALL_ACCESS, // режимы доступа
0, 0, // отображение файла с начала
0); // отображение целого файла
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
printf("%s\n", String);
getchar();
}
Пример 10.2. (html, txt)
Программа first создает в своем адресном пространстве буфер разделяемой памяти, а программа second отображает тот же самый буфер в свое адресное пространство. Затем программа first записывает в этот буфер текстовую строку, а программа second выводит ее содержимое на экран. Обе программы должны быть запущены из одного каталога с уже существующим файлом MyFile.txt. Для наглядности рекомендуется, чтобы длина файла была изначально больше длины строки "Hello, world".
Написание, компиляция и выполнение программы обмена информацией через разделяемый буфер памяти с использованием системной области выгрузки
Рекомендуется модифицировать предыдущую программу для передачи информации через фрагмент разделяемой памяти, спроецированной не в обычный файл, а в системную область выгрузки. Для этого в качестве параметра описателя файла функции CreateFileMapping нужно указать INVALID_HANDLE_VALUE.
Физическая память
Физическая (в данном случае оперативная) память и внешняя память также описываются соответствующими структурами данных.
ОС Windows поддерживает до 4 Гб (некоторые версии и более) физической памяти. Память более 32 Мб считается "большой". Объем памяти можно посмотреть на вкладке "Быстродействие" диспетчера задач. Информация о состоянии страниц физической памяти и их принадлежности процессам находится в базе данных PFN (page frame number), а использование внешней памяти осуществляется через страничные файлы или файлы выгрузки.
Страничные файлы в отличие от файлов, проецируемых в память, хранят только модифицированные страницы, которые по каким-либо причинам выгружены на диск. Страницы, содержащие тексты программ, отображаются в память непосредственно из исполняемых модулей и не хранятся в общесистемных файлах выгрузки.
Структура системных страничных файлов недокументирована. Известно, что в системе может быть до 16 страничных файлов. Информация о страничных файлах находится в разделе HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PagingFiles реестра, однако управление страничными файлами рекомендуется осуществлять через апплет "система" административной консоли управления. У каждого файла подкачки есть начальный и максимальный размер. С целью уменьшения вероятной фрагментации их создают максимального размера.
Полезную информацию об использовании страничных файлов можно получить, наблюдая за счетчиками на вкладке "Производительность", а также с помощью диспетчера задач. Например, счетчик "Page File Bytes" показывает общее число переданных страниц.
Рабочие наборы процессов
В результате связывания адресов часть виртуальных страниц процесса непосредственно отображается в страницы физической памяти. Это множество страниц иногда называют резидентным множеством процесса. В теории операционных систем известно также понятие "рабочего множества" процесса - совокупности страниц, активно использующихся вместе, которая позволяет процессу в течение некоторого периода времени производительно работать, избегая большого количества page fault`ов.
Согласно документации по ОС Windows, рабочим набором процесса называется совокупность физических страниц, выделенных процессу. Размер рабочего набора должен находиться в некоторых пределах, определяемых константами системы в зависимости от суммарного объема физической памяти. Например, если физической памяти достаточно, то рабочий набор процесса должен быть в диапазоне от 50 до 345 страниц. Имея привилегию Increase Scheduling Priority (о привилегиях см. часть V), эти значения можно менять при помощи функции SetProcessWorkingSet.
Если возникает страничная ошибка и рабочий набор процесса не превысил лимита (при слабой загруженности системы допускается даже превышение лимита), система выделяет ему еще один кадр в физической памяти. В противном случае ОС пытается заменять страницы в рабочем наборе этого процесса (локальный алгоритм замещения).
Эволюцию рабочего набора процесса можно "увидеть", наблюдая за счетчиками Working Set и др. в оснастке "Производительность", а также при помощи Диспетчера задач и утилит Pview, Pviewer и ряда других. Важно понимать, что изменение рабочих наборов является следствием страничных нарушений, которые происходят при фактическом обращении к страницам памяти. Простого выделения и передачи памяти здесь недостаточно.