
- •Процессы и задачи в Microsoft Windows
- •Запуск задач
- •Управление запущенными задачами
- •Изменение приоритета задачи
- •Определение приоритета задачи
- •Приостановка и возобновление выполнения задачи
- •Временная приостановка работы задачи
- •Завершение задачи
- •Освобождение идентификатора задачи
- •Критические секции
- •Инициализация критической секции
- •Удаление критической секции
- •Вход в критическую секцию и выход из нее
- •4. Контрольные вопросы
- •5. Содержание работы
- •Создание объекта - событие
- •Открытие объекта - событие
- •Управление состоянием объекта - событие
- •Объекты – событие с автосбросом
- •Создание объекта Mutex
- •Освобождение идентификатора объекта Mutex
- •Открытие объекта Mutex
- •Как завладеть объектом Mutex
- •Освобождение объекта Mutex
- •Как работает семафор
- •Функции для работы с семафорами
- •Создание семафора
- •Уничтожение семафора •
- •Увеличение значения счетчика семафора
- •Уменьшение значения счетчика семафора
- •Определение текущего значения счетчика семафора
- •Создание и открытие ожидаемого таймера
- •Функции для работы с ожидаемым таймером
- •Контрольные вопросы
- •Содержание работы
- •Содержание отчета
- •Теоретический материал
- •7.1. Универсальные функции для работы с файлами в операционных системах Microsoft Windows
- •Функция CreateFile
- •Функция CloseHandle
- •Функции ReadFile и WriteFile
- •Механизм отображения файлов на память
- •Создание отображения файла
- •Выполнение отображения файла в память
- •Открытие отображения
- •Отмена отображения файла
- •Принудительная запись измененных данных
- •Обмен через файлы, отображаемые на память
- •Пример приложения, использующего файлы, отображаемые на память
- •Именованные и анонимные каналы
- •Имена каналов
- •Реализации каналов
- •Создание канала
- •Установка соединения с каналом со стороны сервера
- •Пример приложения, использующего каналы передачи данных Pipes
- •Создание канала Mailslot
- •Открытие канала Mailslot
- •Запись сообщений в канал Mailslot
- •Чтение сообщений из канала Mailslot
- •Определение состояния канала Mailslot
- •Изменение состояния канала Mailslot
- •Пример приложения, использующего каналы передачи данных MailSlot
- •Пример приложения, использующего передачу сообщений между процессами
Пример приложения, использующего файлы, отображаемые на память
В данном приложении используется еще один способ синхронизации приложений – с помощью событий. Мы не будем останавливаться на подробном рассмотрении этого способа. В своем приложении Вы должны использовать этот способ, по аналогии с рассматриваемым примером. Сначала рассмотрим серверную часть приложения.
Сначала объявим переменные, которые будут использоваться в программе, и присвоим им необходимее значения.
// Идентификаторы объектов-событий, которые используются
// для синхронизации задач, принадлежащих разным процессам
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 синхронные или асинхронные операции, аналогично тому, как это можно делать с файлами. В случае использования асинхронных операций необходимо отдельно побеспокоиться об организации синхронизации.