Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ТВП ЛР A5.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
611.84 Кб
Скачать

Пример приложения, использующего файлы, отображаемые на память

В данном приложении используется еще один способ синхронизации приложений – с помощью событий. Мы не будем останавливаться на подробном рассмотрении этого способа. В своем приложении Вы должны использовать этот способ, по аналогии с рассматриваемым примером. Сначала рассмотрим серверную часть приложения.

Сначала объявим переменные, которые будут использоваться в программе, и присвоим им необходимее значения.

// Идентификаторы объектов-событий, которые используются

// для синхронизации задач, принадлежащих разным процессам

HANDLE hEventChar;

HANDLE hEventTermination;

HANDLE hEvents[2];

// Имя объекта-события для синхронизации ввода и отображения

CHAR lpEventName[] = "$MyVerySpecialEventName$";

// Имя объекта-события для завершения процесса

CHAR lpEventTerminationName[] = "$MyVerySpecialEventTerminationName$";

// Имя отображния файла на память

CHAR lpFileShareName[] = "$MyVerySpecialFileShareName$";

// Идентификатор отображения файла на память

HANDLE hFileMapping;

// Указатель на отображенную область памяти

LPVOID lpFileMap;

Создаем объект событие для синхронизации:

// Создаем объект-событие для синхронизации ввода и отображения, выполняемого в

// разных процессах

EventChar = CreateEvent(NULL, FALSE, FALSE, lpEventName);

// Если произошла ошибка, получаем и отображаем ее код, а затем завершаем

// работу приложения

if(hEventChar == NULL)

{ fprintf(stdout,"CreateEvent: Error %ld\n", GetLastError ());

getch();

return 1;

}

Аналогично создаем событие для определения момента завершения работы процесса ввода:

hEventTermination = CreateEvent(NULL, FALSE, FALSE, lpEventTerminationName);

if(hEventTermination == NULL)

{fprintf(stdout,"CreateEvent (Termination): Error %ld\n", GetLastError ());

getch();

return 1;

}

Создаем объект-отображение:

hFileMapping = CreateFileMapping ((HANDLE)0xFFFFFFFF, NULL,

PAGE_READWRITE, 0, 100, lpFileShareName);

// Если создать не удалось, выводим код ошибки

if(hFileMapping == NULL)

{fprintf(stdout,"CreateFileMapping: Error %ld\n",

GetLastError ());

getch();

return 1;

}

Выполняем отображение файла на память в переменную lpFileMap будет записан указатель на отображаемую область памяти:

lpFileMap = MapViewOfFile (hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

// Если выполнить отображение не удалось, выводим код ошибки

if(lpFileMap == 0)

{fprintf(stdout,"MapViewOfFile: Error %ld\n",

GetLastError ());

getch();

return 1;

}

Готовим массив идентификаторов событий для функции WaitForMultipleObjects:

hEvents[0] = hEventTermination;

hEvents[1] = hEventChar;

Цикл отображения. Этот цикл завершает свою работу при завершении процесса ввода:

while(TRUE)

{ // Выполняем ожидание одного из двух событий:

// - завершение клиентского процесса;

// - завершение ввода символа

dwRetCode = WaitForMultipleObjects (2, hEvents, FALSE, INFINITE);

Если ожидание любого из двух событий было отменено, если произошло первое событие (завершение клиентского процесса) или если произошла ошибка, прерываем цикл:

if(dwRetCode == WAIT_ABANDONED_0 ||

dwRetCode == WAIT_ABANDONED_0 + 1 ||

dwRetCode == WAIT_OBJECT_0 ||

dwRetCode == WAIT_FAILED) break;

Читаем символ из первого байта отображенной области памяти, записанный туда клиентским процессом, и отображаем его в консольном окне:

putch (*((LPSTR)lpFileMap));

}

Закрываем идентификаторы объектов-событий

CloseHandle (hEventChar);

CloseHandle (hEventTermination);

Отменяем отображение файла:

UnmapViewOfFile (lpFileMap);

Освобождаем идентификатор созданного объекта-отображения:

CloseHandle (hFileMapping);

Рассмотрим работу клиентской части. Сначала объявим переменные, которые будут использоваться в программе, и присвоим им необходимее значения:

// Идентификаторы объектов-событий, которые используются

// для синхронизации задач, принадлежащих разным процессам

HANDLE hEvent;

HANDLE hEventTermination;

// Имя объекта-события для синхронизации ввода и отображения

CHAR lpEventName[] = "$MyVerySpecialEventName$";

// Имя объекта-события для завершения процесса

CHAR lpEventTerminationName[] = "$MyVerySpecialEventTerminationName$";

// Имя отображния файла на память

CHAR lpFileShareName[] = "$MyVerySpecialFileShareName$";

// Идентификатор отображения файла на память

HANDLE hFileMapping;

// Указатель на отображенную область памяти

LPVOID lpFileMap;

Открываем объект-событие для синхронизации ввода и отображения:

hEvent = OpenEvent(EVENT_ALL_ACCESS, FALS, lpEventName);

if(hEvent == NULL)

{ fprintf(stdout,"OpenEvent: Error %ld\n", GetLastError ());

getch();

return 0;

}

Открываем объект-событие для сигнализации о завершении процесса ввода:

hEventTermination = OpenEvent(EVENT_ALL_ACCESS, FALSE, lpEventTerminationName);

if(hEventTermination == NULL)

{ fprintf(stdout,"OpenEvent (Termination): Error %ld\n", GetLastError ());

getch();

return 0;

}

Открываем объект-отображение:

hFileMapping = OpenFileMapping (FILE_MAP_READ | FILE_MAP_WRITE, FALSE, lpFileShareName);

// Если открыть не удалось, выводим код ошибки

if(hFileMapping == NULL)

{ fprintf(stdout,"OpenFileMapping: Error %ld\n", GetLastError ());

getch();

return 0;

}

Выполняем отображение файла на память. В переменную lpFileMap будет записан указатель на отображаемую область памяти:

lpFileMap = MapViewOfFile (hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

// Если выполнить отображение не удалось, выводим код ошибки

if(lpFileMap == 0)

{ fprintf(stdout,"MapViewOfFile: Error %ld\n", GetLastError ());

getch();

return 0;

}

Цикл ввода. Этот цикл завершает свою работу, когда пользователь нажимает клавишу <ESC>, имеющую код 27:

while(TRUE)

{ // Проверяем код введенной клавиши

chr = getche();

// Если нажали клавишу <ESC>, прерываем цикл

if(chr == 27)

break;

// Записываем символ в отображенную память, доступную серверному процессу

*((LPSTR)lpFileMap) = chr;

// Устанавливаем объект-событие в отмеченное состояние

SetEvent(hEvent);

}

После завершения цикла переключаем оба события в отмеченное состояние для отмены ожидания в процессе отображения и для завершения этого процесса:

SetEvent(hEvent);

SetEvent(hEventTermination);

Закрываем идентификаторы объектов-событий:

CloseHandle (hEvent);

CloseHandle (hEventTermination);

Отменяем отображение файла:

UnmapViewOfFile (lpFileMap);

Освобождаем идентификатор созданного объекта-отображения:

CloseHandle (hFileMapping);

7.3. Каналы передачи данных Pipes

В среде операционной системы Microsoft Windows NT вам доступно такое удобное средство передачи данных между параллельно работающими процессами, как каналы типа Pipe. Это средство позволяет организовать передачу данных между локальными процессами, а также между процессами, запущенными на различных рабочих станциях в сети.

Каналы типа Pipe больше всего похожи на файлы, поэтому они достаточно просты в использовании.

Через канал можно передавать данные только между двумя процессами. Один из процессов создает канал, другой открывает его. После этого оба процесса могут передавать данные через канал в одну или обе стороны, используя для этого хорошо знакомые вам функции, предназначенные для работы с файлами, такие как ReadFile и WriteFile. Заметим, что приложения могут выполнять над каналами Pipe синхронные или асинхронные операции, аналогично тому, как это можно делать с файлами. В случае использования асинхронных операций необходимо отдельно побеспокоиться об организации синхронизации.