Перейти к содержимому

Can t create file mapping что это

  • автор:

Создание именованной общей памяти

Для совместного использования данных несколько процессов могут использовать файлы, сопоставленные с памятью, которые хранит системный файл подкачки.

Первый процесс

Первый процесс создает объект сопоставления файлов путем вызова функции CreateFileMapping с INVALID_HANDLE_VALUE и именем объекта . С помощью флага PAGE_READWRITE процесс имеет разрешение на чтение и запись в памяти через все созданные представления файлов.

Затем процесс использует дескриптор объекта сопоставления файлов, возвращаемый CreateFileMapping в вызове MapViewOfFile , чтобы создать представление файла в адресном пространстве процесса. Функция MapViewOfFile возвращает указатель на представление файла , pBuf . Затем процесс использует функцию CopyMemory для записи строки в представление, к которому могут обращаться другие процессы.

Префикс имен объектов сопоставления файлов «Global\» позволяет процессам взаимодействовать друг с другом, даже если они находятся в разных сеансах сервера терминалов. Для этого требуется, чтобы первый процесс был иметь привилегию SeCreateGlobalPrivilege .

Если процессу больше не нужен доступ к объекту сопоставления файлов, он должен вызвать функцию CloseHandle . Когда все дескрипторы закрыты, система может освободить раздел файла подкачки, который использует объект .

#include #include #include #include #define BUF_SIZE 256 TCHAR szName[]=TEXT("Global\\MyFileMappingObject"); TCHAR szMsg[]=TEXT("Message from first process."); int _tmain() < HANDLE hMapFile; LPCTSTR pBuf; hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BUF_SIZE, // maximum object size (low-order DWORD) szName); // name of mapping object if (hMapFile == NULL) < _tprintf(TEXT("Could not create file mapping object (%d).\n"), GetLastError()); return 1; >pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BUF_SIZE); if (pBuf == NULL) < _tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError()); CloseHandle(hMapFile); return 1; >CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR))); _getch(); UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; > 

Второй процесс

Второй процесс может получить доступ к строке, записанной в общую память первым процессом, вызвав функцию OpenFileMapping , указав то же имя объекта сопоставления, что и первый процесс. Затем он может использовать функцию MapViewOfFile для получения указателя на представление файла , pBuf . Процесс может отобразить эту строку так же, как и любую другую строку. В этом примере отображаемое окно сообщения содержит сообщение «Сообщение от первого процесса», записанное первым процессом.

#include #include #include #include #pragma comment(lib, "user32.lib") #define BUF_SIZE 256 TCHAR szName[]=TEXT("Global\\MyFileMappingObject"); int _tmain() < HANDLE hMapFile; LPCTSTR pBuf; hMapFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, // read/write access FALSE, // do not inherit the name szName); // name of mapping object if (hMapFile == NULL) < _tprintf(TEXT("Could not open file mapping object (%d).\n"), GetLastError()); return 1; >pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BUF_SIZE); if (pBuf == NULL) < _tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError()); CloseHandle(hMapFile); return 1; >MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK); UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; > 

Как избежать ошибки в CreateFileMapping?

5e64ca36b318c151559530.png

При его выполнении вот такой результат:
Что нужно убрать/добавить чтобы код заработал? GetLastError() выдает 6.

  • Вопрос задан более трёх лет назад
  • 978 просмотров

Комментировать

Решения вопроса 1

NikitaWeb @NikitaWeb Автор вопроса

(HANDLE)0xFFFFFFFF заменить на INVALID_HANDLE_VALUE. Проблема в 64-битной версии Windows

Ответ написан более трёх лет назад

Комментировать

Нравится Комментировать

Ответы на вопрос 1

Вообще-то, код рабочий, проверил на Windows 10.

Ответ написан более трёх лет назад

Комментировать

Нравится Комментировать

Ваш ответ на вопрос

Войдите, чтобы написать ответ

cpp

  • C++

Не могу, понять как компьютер перемещает свой знак?

  • 1 подписчик
  • 15 часов назад
  • 70 просмотров

Создание представления в файле

Если требуется просмотреть часть файла, которая не начинается с начала файла, необходимо создать объект сопоставления файлов. Этот объект представляет собой размер части файла, которую вы хотите просмотреть, а также смещение в файле. Например, если вы хотите просмотреть 1 килобайт (1K), который начинается с 131 072 байта (128 КБ), необходимо создать объект сопоставления файлов размером не менее 132 096 байт (129 КБ). Представление начинается с 131 072 байта (128 КБ) в файл и расширяется не менее чем на 1024 байта. В этом примере предполагается степень детализации выделения файлов в 64 КБ.

Степень детализации выделения файлов влияет на начало представления карты. Представление карты должно начинаться со смещения в файле, которое кратно степени детализации выделения файла. Таким образом, данные, которые вы хотите просмотреть, могут быть смещением файла по модулю детализации выделения в представлении. Размер представления — это смещение по модулю данных степени детализации распределения, а также размер данных, которые требуется изучить.

Например, предположим, что функция GetSystemInfo указывает степень детализации выделения 64 КБ. Чтобы изучить 1K данных размером 138 240 байт (135 000 байт) в файле, выполните указанные ниже действия.

  1. Создайте объект сопоставления файлов размером не менее 139 264 байта (136 КБ).
  2. Создайте представление файла, которое начинается со смещения файла, которое является наибольшим, кратным степени детализации выделения файлов, меньшей, чем необходимое смещение. В этом случае представление файла начинается со смещением 131 072 (128 КБ) в файл. Размер представления составляет 139264 байтов (136 КБ) минус 131 072 байта (128 000) или 8 192 байта (8 КБ).
  3. Создайте смещение указателя 7K в представлении, чтобы получить доступ к интересующему вас 1K.

Если нужные данные обрасти границами гранулярности выделения файлов, можно сделать представление больше, чем степень детализации выделения файлов. Это позволяет избежать разбиения данных на части.

В следующей программе показан второй пример выше.

/* This program demonstrates file mapping, especially how to align a view with the system file allocation granularity. */ #include #include #include #define BUFFSIZE 1024 // size of the memory to examine at any one time #define FILE_MAP_START 138240 // starting point within the file of // the data to examine (135K) /* The test file. The code below creates the file and populates it, so there is no need to supply it in advance. */ TCHAR * lpcTheFile = TEXT("fmtest.txt"); // the file to be manipulated int main(void) < HANDLE hMapFile; // handle for the file's memory-mapped region HANDLE hFile; // the file handle BOOL bFlag; // a result holder DWORD dBytesWritten; // number of bytes written DWORD dwFileSize; // temporary storage for file sizes DWORD dwFileMapSize; // size of the file mapping DWORD dwMapViewSize; // the size of the view DWORD dwFileMapStart; // where to start the file map view DWORD dwSysGran; // system allocation granularity SYSTEM_INFO SysInfo; // system information; used to get granularity LPVOID lpMapAddress; // pointer to the base address of the // memory-mapped region char * pData; // pointer to the data int i; // loop counter int iData; // on success contains the first int of data int iViewDelta; // the offset into the view where the data //shows up // Create the test file. Open it "Create Always" to overwrite any // existing file. The data is re-created below hFile = CreateFile(lpcTheFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) < _tprintf(TEXT("hFile is NULL\n")); _tprintf(TEXT("Target file is %s\n"), lpcTheFile); return 4; >// Get the system allocation granularity. GetSystemInfo(&SysInfo); dwSysGran = SysInfo.dwAllocationGranularity; // Now calculate a few variables. Calculate the file offsets as // 64-bit values, and then get the low-order 32 bits for the // function calls. // To calculate where to start the file mapping, round down the // offset of the data into the file to the nearest multiple of the // system allocation granularity. dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran; _tprintf (TEXT("The file map view starts at %ld bytes into the file.\n"), dwFileMapStart); // Calculate the size of the file mapping view. dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE; _tprintf (TEXT("The file map view is %ld bytes large.\n"), dwMapViewSize); // How large will the file mapping object be? dwFileMapSize = FILE_MAP_START + BUFFSIZE; _tprintf (TEXT("The file mapping object is %ld bytes large.\n"), dwFileMapSize); // The data of interest isn't at the beginning of the // view, so determine how far into the view to set the pointer. iViewDelta = FILE_MAP_START - dwFileMapStart; _tprintf (TEXT("The data is %d bytes into the view.\n"), iViewDelta); // Now write a file with data suitable for experimentation. This // provides unique int (4-byte) offsets in the file for easy visual // inspection. Note that this code does not check for storage // medium overflow or other errors, which production code should // do. Because an int is 4 bytes, the value at the pointer to the // data should be one quarter of the desired offset into the file for (i=0; i // Verify that the correct file size was written. dwFileSize = GetFileSize(hFile, NULL); _tprintf(TEXT("hFile size: %10d\n"), dwFileSize); // Create a file mapping object for the file // Note that it is a good idea to ensure the file size is not zero hMapFile = CreateFileMapping( hFile, // current file handle NULL, // default security PAGE_READWRITE, // read/write permission 0, // size of mapping object, high dwFileMapSize, // size of mapping object, low NULL); // name of mapping object if (hMapFile == NULL) < _tprintf(TEXT("hMapFile is NULL: last error: %d\n"), GetLastError() ); return (2); >// Map the view and test the results. lpMapAddress = MapViewOfFile(hMapFile, // handle to // mapping object FILE_MAP_ALL_ACCESS, // read/write 0, // high-order 32 // bits of file // offset dwFileMapStart, // low-order 32 // bits of file // offset dwMapViewSize); // number of bytes // to map if (lpMapAddress == NULL) < _tprintf(TEXT("lpMapAddress is NULL: last error: %d\n"), GetLastError()); return 3; >// Calculate the pointer to the data. pData = (char *) lpMapAddress + iViewDelta; // Extract the data, an int. Cast the pointer pData from a "pointer // to char" to a "pointer to int" to get the whole thing iData = *(int *)pData; _tprintf (TEXT("The value at the pointer is %d,\nwhich %s one quarter of the desired file offset.\n"), iData, iData*4 == FILE_MAP_START ? TEXT("is") : TEXT("is not")); // Close the file mapping object and the open file bFlag = UnmapViewOfFile(lpMapAddress); bFlag = CloseHandle(hMapFile); // close the file mapping object if(!bFlag) < _tprintf(TEXT("\nError %ld occurred closing the mapping object!"), GetLastError()); >bFlag = CloseHandle(hFile); // close the file itself if(!bFlag) < _tprintf(TEXT("\nError %ld occurred closing the file!"), GetLastError()); >return 0; > 

Функционирование менеджера памяти

Программа 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 и ряда других. Важно понимать, что изменение рабочих наборов является следствием страничных нарушений , которые происходят при фактическом обращении к страницам памяти. Простого выделения и передачи памяти здесь недостаточно.

Прогон программы, иллюстрирующей увеличение рабочего набора процесса

Рассмотрим легкую модификацию программы DemoVM, добавив туда операцию записи одного байта на каждую страницу переданной памяти (программа DemoPageFaults.c).

#include #include void main(void)

Наращивание объема переданной памяти и размера рабочего набора будет происходить по нажатию клавиши «Enter». Посмотрим на поведение счетчика «Рабочее множество» для процессов DemoVM и DemoPageFaults. Несмотря на одинаковый объем переданной физической памяти, размеры рабочего набора сильно отличаются. У DemoVM он остается близким к нулю, тогда как у процесса DemoPageFaults идет заметное ступенчатое приращение рабочего набора (см. рис. 10.5)

Наблюдение за изменениями рабочих наборов процессов

Рис. 10.5. Наблюдение за изменениями рабочих наборов процессов

Замещение страниц в рабочем наборе процесса — одна из наиболее ответственных операций. Дело в том, что уменьшение частоты page fault`ов является одной из ключевых задач системы управления памятью (например, известно, что вероятности page fault’а 5*10 -7 оказывается достаточно, чтобы снизить производительность страничной схемы управления памятью на 10%.). Решение этой задачи связано с разумным выбором алгоритма замещения страниц. Если стратегия замещения выбрана правильно, то в оперативной памяти остается только самая актуальная информация, которая может понадобиться в недалеком будущем и которая не нуждается в замещении (на эту тему написано много книг, см., например, [ Карпов ] ).

В ОС Windows используются алгоритмы FIFO (first input first output) в многопроцессорном варианте и LRU — в однопроцессорном. На самом деле применяется не LRU , а его программная реализация NFU (not frequently used), согласно которой страница характеризуется не давностью, а частотой использования. Однако, согласно документации по ОС Windows, алгоритм, осуществляющий модификацию размера рабочего набора процесса, называется именно LRU . Что касается алгоритма FIFO, несмотря на известные недостатки, его применение упрощает обработку ссылок на страницу от нескольких процессоров.

База данных PFN. Страничные демоны

В процессе функционирования операционной системы в физической памяти располагаются рабочие наборы процессов, системный рабочий набор, свободные фрагменты и многое другое. Для учета состояния физической памяти поддерживается база данных PFN (page frame number). Это таблица записей фиксированной длины. Количество записей в ней совпадает с количеством страничных кадров.

Известно, что подсистема виртуальной памяти работает производительно при наличии резерва свободных страничных кадров. Тогда в случае страничной ошибки требуется только одна дисковая операция (чтение), и свободная страница может быть найдена немедленно. Алгоритмы, обеспечивающие поддержку системы в оптимальном состоянии, реализованы в составе фоновых процессов (их часто называют демонами или сервисами), которые периодически «просыпаются» и инспектируют состояние памяти. Их задача — обеспечивать достаточное количество свободных страниц, поддерживая систему в состоянии наилучшей производительности.

Формально, каждая страница физической памяти должна находиться в составе рабочего набора или входить в один из поддерживаемых базой связных списков страниц. Перемещение страниц между списками и рабочими наборами осуществляется системными потоками-демонами, входящими в состав менеджера памяти (см. [ Руссинович ] ). Параметры настройки демонов хранятся в разделе HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management реестра

Чаще всего для обслуживания ошибки страницы в соответствии с требованиями защиты уровня C2 (см. часть V) требуется обнуленная страница, которая извлекается из соответствующего списка. Список обнуленных страниц пополняется потоком обнуления страниц (zero page thread) в фоновом режиме за счет списка свободных страниц. Иногда, например, для отображения файла, обнуленные страницы не нужны, и можно обойтись свободными страницами. Если у рабочего набора процесса отбирается страница, она попадает в список модифицированных страниц или в список свободных страниц. Подсистема записи модифицированных страниц (modified page writer) записывает их содержание на диск, когда количество таких страниц превышает установленный лимит. Страницы проецируемого файла можно сбросить на диск явным образом (при помощи функции FlushViewOfFile ). После записи модифицированная страница попадает в список свободных страниц.

Общее руководство и реализацию общих правил управления памятью осуществляет диспетчер рабочих наборов ( working set manager), который вызывается системным потоком ядра — диспетчером настройки баланса — раз в секунду или при уменьшении объема свободной памяти ниже порогового значения.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *