ОПД.Ф.6 Системное и прикладное программное

advertisement
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РФ
федеральное государственное бюджетное образовательное учреждение
высшего профессионального образования
«Мурманский государственный гуманитарный университет»
(ФГБОУ ВПО «МГГУ»)
УЧЕБНО-МЕТОДИЧЕСКИЙ КОМПЛЕКС
ДИСЦИПЛИНЫ
ОПД.Ф.06
СИСТЕМНОЕ И ПРИКЛАДНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
Основная образовательная программа подготовки специалиста по специальности
010501 «Прикладная математика и информатика»
Утверждено на заседании кафедры
математики и математических методов
в экономике факультета
физико-математического образования,
информатики и программирования
(протокол № 6 от 27 февраля 2013 г.)
Зав. кафедрой _______________О.М. Мартынов
Раздел I
Программа учебной дисциплины
1.1. Автор программы:
старший преподаватель кафедры Яковлева Л.В.
1.2. Рецензенты:
кандидат физико-математических наук, доцент кафедры АГ и ПМ Маренич А.С., кандидат
технических наук, доцент Ланина Н.Р.
1.3. Пояснительная записка:
Целью дисциплины “Системное и прикладное программное обеспечение ” является формирование у студентов целостной системы знаний о программировании системных и
прикладных программ.
В результате изучения курса “Системное и прикладное программное обеспечение”
студенты
должны знать: об основных этапах, методах, средствах и стандартах разработки программного обеспечения; системах программирования, о пользовательском интерфейсе операционной среды, управлении задачами, об особенностях работы с памятью в режиме ядра, управлении вводом/выводом, управлении файлами, синхронизации потоков; об особенностях использования прикладных программ;
о методах создания динамически подключаемых библиотек и COM –
объектов, программировании для Интернета, сетевые протоколы, прикладные системы программирования .NET Framework.
должны уметь: управлять процессами и потоками, исследовать виртуальную память,
использовать проецируемые в память файлы, создавать DLL и подключить ее к приложению, создавать серверы и клиенты обмена данными, создавать COM-объекты, сокеты, Web-сервисы.
Итоговой формой контроля знаний студентов для специальности «Прикладная математика и информатика» - зачет, экзамен.
1.4. Выписка из ГОС ВПО по содержанию дисциплины
ОПД.Ф.06 Системное и прикладное программное обеспечение:
основные этапы, методы, средства и стандарты разработки программного обеспечения; системы программирования (принципы
организации, состав и схема работы); основные типы операционных систем, принципы управления ресурсами в операционной системе; сети ЭВМ и протоколы передачи информации.
1.5. Объем дисциплины и виды учебной работы:
Курс
Семестр
2
4
Трудоемкость
102
Виды учебной работы в часах
Всего
ПР/
Сам.
ЛК
ЛБ
аудит.
СМ
Работа
72
22
24
26
30
Вид итогового контроля
Зачет, экзамен
Предусмотрена разработка одного расчетно-графического задания.
2
1.6. Содержание дисциплины
1.6.1. Разделы дисциплины и виды занятий (в часах). Примерное распределение
учебного времени
Количество часов
№
Наименование раздела, темы
Всего
Сам.
п/п
ЛК
ПР
ЛБ
аудит.
Раб.
1
Классификация программного обеспечения
2
2
2
Управление файлами
6
2
2
2
2
3
Управление потоками и процессами
10
2
4
4
2
4
Синхронизация потоков и процессов
10
2
4
4
4
5
Программирование консольных приложений
5
1
4
Обмен данными между параллельными процес11
6
3
4
4
4
сами
7
Структурная обработка исключений
3
1
2
4
8
Работа с виртуальной памятью
11
3
4
4
4
9
Динамически подключаемые библиотеки
6
2
2
2
4
10 Асинхронная обработка данных
12
4
4
4
6
Всего
72
22
24
26
30
11 Разработка сервисов в Windows
12 Управление безопасностью в Windows
13 Сетевые понятия и протоколы
Сетевое программирование с помощью сокетов
14
Windows
Установка и конфигурирование приложений в
15
.NET Framework 2.0
Инструментарий для мониторинга и безопас16
ность распределенных приложений
1.6.2. Содержание разделов дисциплины
1 Классификация программного обеспечения

Типы программного соединения
 Назначение операционных систем
 Интерфейс программирования Win32 API
 Типы данных в Win32 API
 Объекты ядра и их дескрипторы в Windows
2 Управление файлами
 Накопители на жестких магнитных дисках
 Секторы и кластеры, форматирование дисков
 Функции файловой системы, файловые системы Windows
 Работа с каталогами
 Буферизация ввода-вывода и кэширование ввода-вывода
 Именование файлов в Windows
 Создание и открытие файлов, закрытие и удаление файлов
 Запись данных в файл и чтение данных из файла
 Копирование, перемещение, замещение файла
 Работа с указателем позиции файла
 Определение и изменение атрибутов, размеров файла
 Блокирование файла
3 Управление потоками и процессами
3

4
5
6
7
8
Определение потока, контекст потока, состояние потока, диспетчеризация и
планирование потоков;
 Приостановка и возобновление потоков;
 Псевдодескрипторы потоков
 Создание и завершение процессов;
 Наследование и дублирование дескрипторов
 Приоритеты процессов и потоков;
 Обслуживание потоков;
 Динамическое изменение приоритетов потоков;
Синхронизация потоков и процессов
 Определение синхронизации;
 Программная реализация синхронизации;
 Примитивы синхронизации;
 Критические секции;
 Объекты синхронизации и функции ожидания;
 Мьютексы;
 События;
 Семафоры;
 Взаимоисключающий доступ к переменным: атомарные операции, замена значения переменной, условная замена значения переменной, инкремент и декремент переменной;
 Обнаружение тупиков, восстановление заблокированного процесса, предотвращение тупиков;
Программирование консольных приложений
 Структура консоли;
 Входной буфер консоли, буфер экрана;
 Создание консоли, освобождение консоли, стандартные дескрипторы вводавывода;
 Работа с окном консоли;
 Создание и активизация буфера экрана;
 Определение и установка параметров буфера экрана;
 Ввод-вывод на консоль;
Обмен данными между параллельными процессами
 Способы передачи данных между процессами;
 Передача сообщений;
 Синхронный и асинхронный обмен данными;
 Буферизация;
 Работа с анонимными каналами;
 Работа с именованными каналами;
 Работа с почтовыми ящиками в Windows;
Структурная обработка исключений
 Исключения и их обработчики;
 Получение кода исключения;
 Генерация программных исключений;
 Необработанные исключения;
 Обработка вложенных исключений;
 Встраивание SEN в механизм исключений С++;
 Финальная обработка исключений;
Работа с виртуальной памятью
 Организация виртуальной памяти;
4
 Состояние виртуальной памяти процесса;
 Резервирование, распределение и освобождение виртуальной памяти;
 Изменение атрибутов доступа к виртуальной странице;
 Создание и удаление кучи;
 Распределение и освобождение памяти из кучи;
 Проверка состояния кучи;
 Уплотнение кучи;
 Концепция механизма отображения файлов в память;
 Создание и открытие объекта, отображающего файл;
 Отображение файла в память;
 Обмен данными между процессами через отображаемый в память файл;
 Сброс вида в файл;
9 Динамически подключаемые библиотеки
 Концепция динамически подключаемых библиотек;
 Создание DLL;
 Динамическая загрузка и отключение DLL;
 Использование DLL;
 Использование файла определений;
 Статическая загрузка DLL;
 Динамическая локальная память потока;
 Распределение и освобождение локальной памяти потока;
 Запись и чтение из локальной памяти потока;
 Статическая локальная память потока;
10 Асинхронная обработка данных
 Механизм асинхронного вызова процедур;
 Установка асинхронных процедур;
 Приостановка потока;
 Ожидание события;
 Оповещение и ожидание события;
 Концепция асинхронного ввода-вывода;
 Асинхронная запись данных;
 Блокирование файлов;
 Определение состояния асинхронной операции ввода-вывода;
 Отмена асинхронной операции ввода-вывода;
 Процедуры завершения ввода-вывода;
 Асинхронная запись данных с процедурами завершения;
 Асинхронное чтение данных с процедурами завершения;
 Концепция порта завершения;
 Создание порта завершения;
 Получение пакета из порта завершения;
 Создание и открытие ожидающего таймера;
 Установка ожидающего таймера;
 Отмена ожидающего таймера;
 Процедуры завершения ожидания;
1
Следующие темы включены в дисциплину “Дополнительные главы системного и прикладного программного обеспечения”(факультатив), так как на
дисциплину “Системное и прикладное программное обеспечение ” отведено
всего 22 лекционных часа.
Разработка сервисов в Windows
5
2
3
4
 Концепция сервиса
 Структура сервиса
 Организация функции main сервиса;
 Организация функции ServiceMain;
 Организация обработчика управляющих команд;
 Открытие доступа к базе данных сервисов;
 Установка сервиса и удаление сервиса;
 Открытие доступа и запуск сервиса;
 Определение и изменение состояния сервиса;
 Управление сервисом;
 Блокирование базы данных сервисов;
Управление безопасностью в Windows
 Атрибуты безопасности;
 Общий обзор средств безопасности: дескриптор безопасности;
 Списки контроля доступа;
 Права объектов и доступ к объектам
 Инициализация дескриптора безопасности;
 Управляющие флаги дескриптора безопасности;
 Идентификаторы безопасности;
 Работа с ACL;
 Чтение и запись дескрипторов безопасности;
 Защита объектов ядра и коммуникаций;
 Обзор дополнительных возможностей защиты объектов
 Удаление элементов ACE;
 Абсолютные и самоопределяющиеся относительные дескрипторы
безопасности;
 Системные списки ACL;
 Информация, хранящаяся в маркерах доступа;
 Управление идентификаторами SID;
 Протокол защищенных сокетов.
Сетевые понятия и протоколы
 Модель OSI;
 Протокол Ethernet;
 Физические компоненты сетей;
 Internet Protocol;
 TCP протокол;
 UDP протокол;
 HTTP протокол;
 Протоколы электронной почты;
 Серверы доменных имен;
 XML Web-сервисы;
Сетевое программирование с помощью сокетов Windows
 Сокеты Windows
 Инициализация Winsock;
 Создание сокета;
 Серверные функции сокета;
 Связывание сокета;
 Перевод связанного сокета в состояние прослушивания;
 Прием клиентских запросов соединения;
6










5
6
Отключение и закрытие сокетов;
Клиентские функции сокета;
Установление клиентского соединения с сервером;
Отправка и получение данных;
Сравнение именованных каналов и сокетов;
Сравнение серверов именованных каналов и сокетов;
Сравнение клиентов именованных каналов и сокетов;
Внутрипроцессные серверы;
Ориентированные на строки сообщения, точки входа DLL и TLS;
Решение проблемы долговременных состояний в многопоточной среде;
 Использование дейтаграмм для удаленного вызова процедур;
 Перекрывающийся ввод-вывод с использованием Windows Sockets;
Установка и конфигурирование приложений в .NET Framework 2.0
 Общие параметры;
 Параметры настройки приложения;
 Создание и удаление разделов реестра;
 Использование утилиты .NET Framework 2.0 Configuration;
 Изменение и восстановление параметров настройки приложения;
 Получение и хранение параметров настройки;
 Реализация интерфейсов конфигурации;
Инструментарий для мониторинга и безопасность распределенных
приложений
 Создание и удаление журнала событий;
 Запись в журнал событий и чтение из него;
 Запись вывода, генерируемого кодом;
 Отладочные атрибуты;
 Мониторинг производительности;
 Обнаружение управляющих событий;
 Регистрация управляющих событий в журнале.
1. 6. 3. Темы для самостоятельного изучения.
№
Наименование
Форма самостоятельной работы
Кол-во
Форма контроля
п/п
раздела
самостоятельно
часов
выполнения само-
дисциплины.
стоятельной работы
Тема.
1
Управление
Исследуйте, чем отличается использо-
файлами
вание файловой системы NTFS от
2
Реферат
программы…
FAT32 на Вашем компьютере. Создание пользовательской файловой системы.
2
Управление
потоками
процессами
Возможные ловушки и распростраи
2
Реферат
ненные ошибки при разработке много
7
поточных программ.
API облегченных е потоков
3
Синхронизация Влияние синхронизации на производи-
программа
4
потоков и про- тельность. Создание программы для
цессов
Реферат,
программа
исследования факторов производительности для использования CS или
мьютексов при различных факторах:
при различных количествах рабочих
потоков, времени удержания блокировки и т.д.
4
Обмен данны- Разработайте « процессор задач», реами между пализующий следующие возможности:
раллельными
процессами
1.jobbg -использует часть командной
4
Программа
4
Программа
4
Реферат
строки в качестве имени задачи или
нового процесса, новый процесс может
получать собственную консоль или
выполняться как отсоединенный.
2. jobs -выводит список текущих активных задач, снабжая каждую из задач порядковым номером и идентификатором процесса.
3. kill -прекращает выполнение задачи
5
Структурная
Создайте приложение, в котором
обработка исопределены обработчики исключений
ключений
и завершения. В программе обрабатывается несколько файлов, имена файлов указываются в командной строке,
после обработки -преобразования всех
букв в верхний регистр, файлы перезаписываются с именем , состоящим из
исходного имени плюс префикс
UP_(upper) .
6
Работа с вирту- Ограничения метода отображения
альной памяфайлов. Создайте приложение, реалитью
8
зующее использование базовых указа-
Программа
телей при сопровождении индексных
файлов.
7
Динамически
подключаемые
библиотеки
Использование библиотеки С в пото-
4
ках. Создайте библиотеку с многопо-
Реферат
Программа
точной поддержкой.
8
Асинхронная
обработка
данных
Обзор методов асинхронного вводавывода Windows. Модифицируйте
6
Реферат
Программы
клиент именованного канала, введя в
него перекрывающийся ввод-вывод.
Напишите программу, в которой используются порты завершения вводавывода для работы сервера именованных каналов.
1.7. Методические рекомендации по организации изучения дисциплины.
1. Тематика и планы практических занятий по изученному материалу
Практическое занятие № 1 (2часа)
Тема: Управление файлами
Цель: Изучить использование функций Win32API и стандартной библиотеки С++
для работы с файлами
Задание.
№ 1. Скомпилируйте, скомпонуйте и выполните каждую их трех программ, предназначенных для копирования файлов:
//* Базовая программа копирования файлов
Реализация, использующая библиотеку C. */
/* cp файл1 файл2: Копировать файл1 в файл2. */
#include <stdio.h>
#include <errno.h>
#define BUF_SIZE 256
int main (int argc, char *argv [])
{
FILE *in_file, *out_file;
char rec [BUF_SIZE];
size_t bytes_in, bytes_out;
9
if (argc != 3) {
printf ("Использование: cpC файл1 файл2\n");
return 1;
}
in_file = fopen (argv [1], "rb");
if (in_file == NULL) {
perror (argv [1]);
return 2;
}
out_file = fopen (argv [2], "wb");
if (out_file == NULL) {
perror (argv [2]);
return 3;
}
/* Обработать входной файл по одной записи за один раз. */
while ((bytes_in = fread (rec, 1, BUF_SIZE, in_file)) > 0) {
bytes_out = fwrite (rec, 1, bytes_in, out_file);
if (bytes_out != bytes_in) {
perror ("Неустранимая ошибка записи.");
return 4;
}
}
fclose (in_file);
fclose (out_file);
return 0;
}
/* Базовая программа копирования файлов cp.
Реализация, использующая Windows. */
/* cpW файл1 файл2: Копировать файл1 в файл2. */
#include <windows.h>
#include <stdio.h>
#define BUF_SIZE 256
int main (int argc, LPTSTR argv [])
{
HANDLE hIn, hOut;
DWORD nIn, nOut;
CHAR Buffer [BUF_SIZE];
if (argc != 3) {
printf ("Использование: cpW файл1 файл2\n");
1
0
return 1;
}
hIn = CreateFile (argv [1], GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (hIn == INVALID_HANDLE_VALUE) {
printf ("Невозможно открыть входной файл. Ошибка: %x\n",
GetLastError ());
return 2;
}
hOut = CreateFile (argv [2], GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOut == INVALID_HANDLE_VALUE) {
printf ("Невозможно открыть выходной файл. Ошибка: %x\n",
GetLastError ());
return 3;
}
while (ReadFile (hIn, Buffer, BUF_SIZE, &nIn, NULL) && nIn > 0) {
WriteFile (hOut, Buffer, nIn, &nOut, NULL);
if (nIn != nOut) {
printf ("Неустранимая ошибка записи: %x\n", GetLastError ());
return 4;
}
}
CloseHandle (hIn);
CloseHandle (hOut);
return 0;
}
/* Базовая программа копирования файлов cp.
Реализация, в которой для повышения удобства использования и
производительности программы используется функция Windows CopyFile. */
/* cpCF файл1 файл2: Копировать файл1 в файл2. */
#include <windows.h>
#include <stdio.h>
int main (int argc, LPTSTR argv [])
{
if (argc != 3) {
printf ("Использование: cpCF файл1 файл2\n");
return 1;
}
if (!CopyFile (argv [1], argv [2], FALSE)) {
printf ("Ошибка при выполнении функции CopyFile: %x\n", GetLastError ());
return 2;
}
return 0;
}
№ 2. Ознакомьтесь с одной из сред разработки приложений, например, Microsoft Visual
Studio .NET. Научитесь создавать в выбранной среде консольные приложения. Научитесь
использовать отладчик.
1
1
№ 3.Определите, как изменится поведение программы 1.1, если входной файл открывать в
двоичном режиме, а выходной – в текстовом, или наоборот.
№ 4. Выполните для каждой из программ хронометраж при копировании файлов большого размера. Получите соответствующие данные для как можно большего числа различных
вариантов и сравните полученные результаты между собой. Анализ результатов представьте в виде таблицы.
Контрольные вопросы
1. Какие файловые системы поддерживает Windows NT5?
2. Какие определены правила именования файлов в Windows NT5?
3. Объясните назначение параметров в функции Win32 API CreateFile?
4. Чем символы Unicode отличаются от символов ASCII?
5. В функция ReadFile и WriteFile для чего используется последний параметр ?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
 Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual
C++ 6.00 для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый
дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3

Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.М.: ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 2 -1(2 часа)
Тема: Управление потоками и процессами
Цель: Изучить использование функций для работы с потоками
Краткие теоретические сведения
Определение потока
Потоком в Windows называется объект ядра, которому ОС выделяет процессорное время
для выполнения заданной функции. Каждый поток обладает следующими ресурсами:
1. код исполняемой функции;
2. набор регистров процессора;
3. стек для работы ОС;
1
2
4. стек для работы приложения;
5. маркер доступа, который содержит информацию для системы безопасности.
Все эти ресурсы образуют контекст потока в Windows. Каждый поток в Windows
имеет кроме дескриптора уникальный идентификатор. Различают потоки двух типов:
системные и пользовательские. Системные потоки запускаются ядром операционной
системы и выполняют различные сервисы ОС. Пользовательские потоки запускаются
приложением и служат для решения пользовательских задач. В работающем приложении различаются потоки двух типов: рабочие потоки, потоки интерфейса пользователя. Потоки интерфейса пользователя связаны с окнами и выполняют обработку сообщений, поступающих этим окнам. Рабочие потоки выполняют различные фоновые
задачи.
Создается поток функцией
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpsa,
DWORD cbStack,
LPTHREAD_START_ROUTINE pfnStartAddr,
LPVOID lpvParam,
DWORD tdwCreate,
LPDWORD pdwThreadID);
При успешном завершении функция CreateThread возвращает дескриптор созданного
потока и его идентификатор. Назначение параметров функции:
параметр LPSECURITY_ATTRIBUTES lpsa устанавливает атрибуты защиты создаваемого
потока, обычно используется значение NULL, это означает, что ОС сама установит атрибуты защиты;
параметр DWORD cbStack определяет размер стека, который выделяется потоку при запуске, если этот параметр равен 0, то потоку выделяется стек объемом 1Мбайт;
параметр LPTHREAD_START_ROUTINE pfnStartAddr указывает на исполняемую потоком функцию. Эта функция должна иметь прототип:
DWORD WINAPI name_function (LPVOID lpPatameters);
Функции передается параметр, который является указателем на пустой тип. Это ограничение следует из того, что функция потока вызывается ОС, а не прикладной программой.
Так как функции потоков вызываются ОС, то они также получили название функции обратного вызова;
параметр lpvParam идентичен параметру lрvРаrат функции потока. CreateTbread лишь
передает этот параметр по эстафете той функ ции, с которой начинается выполнение создаваемого потока. Таким образом, данный параметр позволяет передавать функции потока какое-либо инициализирующее значение. Оно может быть или просто числовым значением, или указателем на структуру данных с дополнительной информацией.
Вполне допустимо и даже полезно создавать несколько потоков, у которых в качестве
входной точки используется адрес одной и той же функции. Например, можно реализовать Web-сервер, который обрабатывает каждый клиентский запрос в отдельном потоке.
При создании каждому потоку передается свое значение lрvParam.
параметр DWORD tdwCreate определяет в каком состоянии будет создан поток
Этот параметр определяет дополнительные флаги, управляющие созданием потока. Он
принимает одно из двух значений. 0 (исполнение потока начинается немедленно) или
CREATE_SUSPENDED. В последнем случае система создает поток, инициализирует его и
приостанавливает до последующих указаний.
Флаг CREATE_SUSPENDED позволяет программе изменить какие-либо свойства потока
перед тем, как он начнет выполнять код
параметр LPDWORD pdwThreadID — это адрес переменной типа DWORD, в которой
функция возвращает идентификатор, приписанный системой новому потоку. В Windows
1
3
2000 и Windows NT 4 в этом параметре можно передавать NULL (обычно так и делается).
Тем самым Вы сообщаете функции, что идентификатор потока не интересует
Функции завершения потока
Любой поток процесса может сам завершить свое выполнение, вызвав функцию
ExitThread, но более обычным способом самостоятельного завершения потока является
возврат из функции потока с использованием кода завершения в качестве возвращаемого
значения. По завершении выполнения потока память, занимаемая ее стеком, освобождается. В случае если поток был вызван в библиотеке DLL, будет вызвана соответствующая
точка входа DllMain с указанием флага DLL_THREAD_DETACH
VOID ExitThread (DWORD dwExitCode)
Когда завершается выполнение последнего потока, завершается и выполнение самого
процесса.
Выполнение потока также может быть завершено другим потоком с помощью функции
TerminateThread, но освобождения ресурсов потока при этом не происходит, обработчики
завершения не выполняются и уведомления библиотекам DLL не посылаются.
Поток, выполнение которого было завершено, продолжает существовать до тех, пока посредством функции CloseHandle не будет закрыт ее последний дескриптор.
BOOL GetExitCodeThread (
HANDLE hThread,
LPDWORD lpExitCode)
Параметр lpExitCode будет содержать код завершения потока, указывающий на его состояние. Если поток не
завершен, значение этой переменной будет равно STILL_ACTIVE
Идентификация потоков
Функция GetCurrentThread –возвращает ненаследуемый псевдодескриптор вызывающего
потока.
Функция – GetCurrentThreadId позволяет получить идентификатор потока, а не его дескриптор.
Функция GetThreadId - позволяет получить идентификатор потока, если известен его дескриптор; эта функция требует использования Windows Server 2003.
Функция OpenThread – создает дескриптор потока по известному идентификатору.
Дополнительные функции управления потоками
1. Функция GetProcessIdOfThread , требующая использования Windows Server 2003, позволяет получать идентификатор процесса, которому принадлежит поток по известному дескриптору потока. Эту функцию можно задействовать в программах, предназначенных для управления потоками, принадлежащими другим процессам, или для взаимодействия с такими потоками. Если необходимо получить дескриптор процесса, применяйте для этого функцию OpenProcess
Функция GetThreadIOPendingFlag позволяет определить, имеются ли у потока на который
указывает дескриптор, необслуженные запросы ввода/вывода. Например, поток мог быть
заблокирован во время выполнения операции ReadFile. В качестве результата возвращается состояние потока во время выполнения данной функции, фактическое состояние может в любой момент измениться, если целевой поток завершает или начинает выполнение
операции. Эта функция требует использование NT 5.1
и поэтому доступна лишь в Windows XP и Windows Server 2003.
Приостановка и возобновление выполнения потока
Для каждого потока поддерживается счетчик приостановок (suspend count),
И выполнение потока может быть продолжено лишь в том случае, если значение этого
счетчика 0. Поток может увеличивать или уменьшать значение счетчика приостановок
другого потока с помощью функций SuspendThread и ResumeThread . Поток можно создать
в приостановленном состоянии со счетчиком приостановок 1.
DWORD ResumeThread (HANDLE hThread)
DWORD SuspendThread (HANDLE hThread)
1
4
В случае успешного выполнения обе функции возвращают предыдущее значение счетчика
приостановок, иначе - 0xFFFFFFFF
Ожидание завершения потока
Поток может дожидаться завершения выполнения другого потока. При вызове функций
ожидания WaitForSingleObject() и WaitForMultipleObjects() используются дескрипторы
потоков, а также дескрипторы процессов. В массиве, передаваемом функции
WaitForMultipleObjects() могут быть одновременно указаны дескрипторы потоков, процессов и других объектов. Допустимое количество объектов, одновременно ожидаемых
функцией WaitForMultipleObjects() ограниченно значением MAXIMUM_WAIT_OBJECTS
(64), но при большом количестве потоков можно воспользоваться серией вызовов функций ожидания. Функция ожидания дожидается, пока объект, указанный дескриптором, не
перейдет в сигнальное состояние. В случае потоков объект потока переводится в сигнальное состояние при помощи функций ExitThread и TerminateThread, что приводит к освобождению всех других потоков, дожидающихся перехода данного объекта в сигнальное
состояние, включая и те потоки, которые могли оставаться в состоянии ожидания и впоследствии, после того как поток завершится. Дескриптор потока, перешедший в сигнальное состояние, не выходит из этого состояния, в отличии от некоторых объектов, например, мьютексов, событий.
Удаленные потоки
Функция CreateRemoteThread позволяет создавать потоки, выполняющиеся в другом
процессе. По сравнению с функцией CreateThread в ней имеется один дополнительный
параметр для указания дескриптора процесса, а адрес функции, задающий начальный адрес нового потока, должен находиться в адресном пространстве целевого процесса.
Использование библиотеки С в потоках
Исторически так сложилось, что библиотека С была рассчитана на применение в однопоточных процессах, поэтому для хранения промежуточных данных многие функции используют области глобальной памяти. Библиотеки, в которых отсутствует многопоточная поддержка, не являются безопасными с точки зрения одновременного выполнения нескольких потоков. Microsoft C предлагает библиотеку LIBCMT.LIB, которая обеспечивает
многопоточную поддержку. Но также следует использовать функцию _beginthreadex, а
не CreateThread.
typedef unsigned ( stdcall *PTHREAD START) (void *)
#define chBEGINTHREADEX(psa cbStack pfnStartAddr \
pvParam fdwCreate pdwThreadID) \
((HANDLE) _beginthreadex( \
(void *) (psa) \
(unsigned) (cbStack), \
(PTHREAD_START) (pfnStartAddr) \
(void *) (pvParam) \
(unsigned) (fdwCreate) \
(unsigned *) (pdwThreadID)))
Для завершения потока вместо функции ExitThread применяется функция _endthreadex.
Аргументы функции _beginthreadex в точности совпадают с функцией CreateThread,
однако типы данных . Windows для этой функции не определены, поэтому тип возвращаемого значения функции _beginthreadex необходимо привести к типу HANDLE.
Microsoft поставляет с Visual С++ шесть библиотек С/С++. Их краткое описание пред
ставлено в следующей таблице.
Имя библиотеки
Описание
1
5
LibC.lib
Статически подключаемая библиотека для однопоточных приложений
LibCD.lih
Отладочная версия статически подключаемой библиотеки для однопо
LibCMt.lib
Статически подключаемая библиотека для многопоточных приложений
LibCMtD.lib
MSVCRt.lib
Отладочная версия статически подключаемой библиотеки для много
Библиотека импорта для динамического подключения рабочей версии
MSVCRtD.lib
Библиотека импорта дли динамического подключения отладочной версии
MSVCRtD.dll; поддерживает как одно-, так и многопоточные приложения
При реализации любого проекта нужно знать, с какой библиотекой его следует связать.
Конкретную библиотеку можно выбрать в диалоговом окне Project Settings: на вкладке
С/С++ в списке Category укажите Code Generation, а в списке Use Run-Time Library — одну из шести библиотек. Заметьте, что функция _beginthreadex существует только в многопоточных версиях библиотеки С/С++. Связав проект с однопоточной библиотекой, Вы
получите от компоновщика сообщение об ошибке "unresolved external symbol». Конечно,
это сделано специально, потому что однопоточная библиотека не может корректно работать в многопоточном приложении. Также обратите внимание на то, что при создании нового проекта Visual Studio по умолчанию выбирает однопоточную библиотеку.
Поскольку Microsoft поставляет исходный код библиотеки С/С++, несложно разобраться в
том, что такого делает _beginthreadex, чего не делает CreateThread, На дистрибутивном
компакт-диске Visual Studio ее исходный код содержится в файле Threadex.c. Вот представлены самые интересные места:
unsigned long _cdocl _beginthreadex ( void *psa,
unsigned cbStack,
unsigned (__stdcall * pTnStartAddr) (void *),
void *pvParam,
unsigned fdwCreate,
unsigned *pdwThreadID)
{
_ptiddata ptd; // указатель на блок данных потока
unsigned long thdl, // описатель потока
// выделяется блок данных для нового потока
if ((ptd = _calloc_crt(1, sizeof(struct tiddata))) == NULl)
goto error_returnж
// инициализация блока данных
initptd(ptd);
// здесь запоминается нужная функция потока и параметр,
// который мы хотим поместить в блок данных
ptd->_initaddr = (void *) pfnStartAddr;
ptd->_initarg = pvParam;
// создание потока
thdl = (unsigned long)
CreateThread(psa, cbStack, _threadstartex, (PVOID) ptd, fdwCreate, pdwThrcadID);
if (thdl == NULl) {
// создать поток не удалось, проводится очистка и сообщается об ошибке
goto error_return;
}
// поток успешно создан; возвращается его описатель
return(thdl);
error_return:
// ошибка! не удалось создать блок данных или сам поток
_free_crt(ptd);
return((unsigned long)0L);
}
Несколько важных моментов, связанных с _beginthreadex
1. Каждый поток получает свой блок памяти tiddata, выделяемый из кучи, которая
принадлежит библиотеке С/C++ (Структура tiddata определена в файле Mtdll.h.
1
6
Адрес функции потока, переданный _beginthreadex, запоминается в блоке памяти
tiddata Там же сохраняется и параметр, который должен быть передан этой функции
3. Функция _beginthreadex вызывает CreateThread, так как лишь с ее помощью операционная система может создать новый поток
4. При вызове CreateThread сообщается, что она должна начать выполнение нового
потока с функции _threadstartex, а не с того адреса, на который указывает
fnStartAddr Кроме тою, функции потока передается не параметр рvParam а адрес
структуры tiddata
5. Если все проходит успешно, beginthreadex, как и CreateThread, возвращает описатель потока, в ином случае возвращается NULL
2.
Функция _endthreadex (ее исходный код тоже содержится в файле Threadex.c). Вот как
она выглядит (в псевдокоде)
void _cdecl _endthreadex (unsigned retcode)
{
_ptiddata ptd;
// указатель на блок данных потока
// здесь проводится очистка ресурсов, выделенных для поддержки операций
// над числами с плавающей точкой (код не показан)
// определение адреса блока tiddata данного потока
ptd = _getptd();
// высвобождение блока tiddata
_freeptd(ptd);
// завершение потока
ExitThread(retcode);
}
Несколько важных моментов, связанных с _endthreadex
1. Библиотечная функция _getptd обращается к Windows-функции TlsGetValue, которая
сообщает адрес блока памяти tiddata вызывающего потока
2. Этот блок освобождается, и вызовом ExttThread поток разрушается. При этом, конечно, передается корректный код завершения.
Прямое обращение к функции ExitThread следует избегать, так как это приводит к уничтожению вызывающего потока и не позволяет ему вернуться из выполняемой в данный
момент функции А поскольку она не возвращает управление, любые созданные и С++объекты не разрушаются.
Разработчики Microsoft Visual C++ кое-что сделали, чтобы свести к минимуму вероятность утечки памяти. Если хотите самостоятельно уничтожить свой поток, можете вызвать из него _endthreadex (вместо ExitTbread) и тем самым освободить его блок tiddata.
Динамически подключаемая версия библиотеки С/С++ вполне универсальна ее могут использовать любые выполняемые приложения и DLL, которые обращаются к библиотечным функциям. По этой причине данная библиотека существует лишь в многопоточной
версии. Поскольку она поставляется в виде DLL, ее код не нужно вклю чать непосредственно в EXE- и DLL-модули, что существенно уменьшает их размер. Кроме того, если
Microsoft исправляет какую-то ошибку в такой библиотеке, то и программы, построенные
на ее основе, автоматически избавляются от этой ошибки
Стартовый код из библиотеки С/С++ создает и инициализирует блок данных для первичного потока приложения. Это позволяет без всяких опасений вызывать из первичного по1
7
тока любые библиотечные функции А когда первичный поток заканчивает выполнение
своей входной функции, блок данных завершаемого потока освобождается самой библиотекой Более того, стартовый код делает все необходимое для структурной обработки исключений, благодаря чему из первичного потока можно спокойно обращаться и к библиотечной функции signal.
Библиотечные функции, которые лучше не вызывать
В библиотеке С/С++ содержится две функции:
unsigned long _beginthread( void (__cdecl *stait_address)(void *), unsigned
stack_size, void *arglist);
и
void _endthread(void);
Первоначально они были созданы для того, чем теперь занимаются новые функ ции
_beginthreadex и _endthreadex. Нo, как видите, у _begintbread параметров меньше, и, следовательно, ее возможности ограничены в сравнении с полнофункциональной
beginthreadex. Например, работая с _beginthread, нельзя создать поток с атрибутами защиты, отличными от присваиваемых по умолчанию, нельзя создать поток и тут же его задержать — нельзя даже получить идентификатор потока. С функцией _endthread та же история; она не принимает никаких параметров, а это значит, что по оконча нии работы потока его код завершения всегда равен 0.
Однако с функцией _endthread дело обстоит куда хуже, чем кажется: перед вызо вом
ExitThread она обращается к CloseHandle и передает ей описатель нового потока. Взгляните на следующий код:
DWORD dwExitCode;
HANDLE hThreatf = _beglntnread(...);
GetExitCodeThread(hThread &dwExitCode);
CloseHandle(hThread);
Весьма вероятно, что созданный поток отработает и завершится еще до того, как первый
поток успеет вызвать функцию GetExitCodeThread. Если так и случится, значе ние в
hThread окажется недействительным, потому что _endtbread уже закрыла описатель нового потока. И, естественно, вызов CloseHandle дает ошибку.
Задание
№1
Создайте консольное приложение, в котором запускается вторичный поток. В этом потоке вызывается функция, считывающая строку и и в этой функции подсчитывается количество повторений каждого символа.
#include <windows.h>
#include <iostream>
volatile int n;
DWORD WINAPI Add(LPVOID iNum)
{
//
}
int main()
{
int inc = 10;
HANDLE hThread;
DWORD IDThread;
cout << "n = " << n << endl;
// запускаем поток Add
hThread = CreateThread(NULL, 0, Add, (void*)inc, 0, &IDThread);
if (hThread == NULL)
return GetLastError();
// ждем, пока поток Add закончит работу
WaitForSingleObject(hThread, INFINITE);
// закрываем дескриптор потока Add
1
8
CloseHandle(hThread);
cout << "n = " << n << endl;
return 0;
}
№2
Создайте консольное приложение, в котором используются функции остановки вторичного потока на заданный промежуток времени, например,
Sleep(100);
функция SuspendThread(идентификатр_потока) остановки потока и функция
ResumThread(идентификатр_потока) возобновления потока. Для пользователя вводится
приглашение выбрать вариант дальнейшего хода программы:
вывести сообщение со значением переменной nCount ;
#include <windows.h>
#include <iostream.h>
volatile UINT nCount;
volatile DWORD dwCount;
void thread()
{
for (;;)
{
nCount++;
Sleep(???);
}
}
int main()
{
HANDLE hThread;
DWORD IDThread;
char c;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread, NULL,
0, &IDThread);
if (hThread == NULL)
return GetLastError();
for (;;)
{
// cout <<????????? << endl;
// cout << ???????? << endl;
// cout << ????????? << endl;
// cout << ?????
cin >> c;
if (c == 'n')
break;
switch (c)
{
case 'y':
1
9
???
case 's':
// ???????????????? ????? thread
case 'r':
??????
cout <<
break;
}
}
// ????????? ?????????? ?????? thread
TerminateThread(hThread, 0);
// ????????? ?????????? ?????? thread
CloseHandle(hThread);
return 0;
}
Контрольные вопросы
1. В чем состоят особенности использования функции _beginthreadex?
2. В чем различие между дескриптором и идентификатором потока?
3. Какие функции позволяют приостановить и возобновлять выполнение потока?
4. Что представляет собой поток?
5. Что означает понятие «в контексте потока»?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
 Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual
C++ 6.00 для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый
дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3

Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.М.: ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 2-2 (2часа)
Тема: Управление потоками и процессами
Цель: Изучить функции по использованию процессов в Windows
Краткие теоретические сведения
В Windows под процессом понимается объект ядра, которому принадлежат системные ресурсы, используемые исполняемым приложением. Каждый процесс в Windows владеет
следующими ресурсами:
виртуальным адресным пространством;
2
0
рабочим множеством страниц в реальной памяти;
маркером доступа, содержащим информацию для системы безопасности;
таблицей для хранения дескрипторов объектов ядра;
Кроме дескриптора, каждый процесс в Windows имеет свой идентификатор, который
является уникальным для процессов, выполняющихся в системе.
Создание процессов
Новый процесс в Windows создается вызовом функции CreateProcess,
BOOL CreateProcess (
LPCTSTR lpApplicatiomName,//имя исполняемого модуля
LPTSTR lpCommandLine, //командная строка
LPSECURITY_ATTRIBUTES lpProcessAttributes,//защита процесса
LPSECURITY_ATTRIBUTES lpThreadAttributes,//защита потока
BOOL bInheritHandles,//признак наследования дескриптора
DWORD dwCreationFlags,//флаги создания процесса
LPVOID lpEnvironment, //блок новой среды окружения
LPCTSTR lpCurrentDirectory,//текущий каталог
LPSTARTUPINFO lpStartUpInfo,//вид главного окна
LPPROCESS_INFORMATION lpProcessInformation //информация о процессе);
Первый параметр LPCTSTR lpApplicatiomName определяет строку с именем исполняемого файла, который имеет тип exe и будет запускаться при создании нового процесса. Эта
строка должна заканчиваться нулем и содержать полный путь к исполняемому файлу.
Например, создайте программу, которая выводит на консоль свое имя и параметры
#include <conio.h>
int main(int argc, char *argv[])
{
int i;
_cputs("I am created.");
_cputs("\nMy name is: ");
_cputs(argv[0]);
for (i = 1; i < argc; ++i)
_cprintf ("\n My %d parameter = %s", i, argv[i]);
_cputs("\nPress any key to finish.\n");
_getch();
return 0;
}
2
1
Полученный exe-файл сохраните на диске. Например:
Теперь нужно созданный файл запустить как новый процесс.
#include <windows.h>
#include <conio.h>
int main()
{
char lpszAppName[] = "имя_диска:\\полное_имя.exe";
STARTUPINFO si;
PROCESS_INFORMATION piApp;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// создаем новый консольный процесс
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE, NULL, NULL, &si, &piApp))
{
_cputs("The new process is not created.\n");
_cputs("Check a name of the process.\n");
_cputs("Press any key to finish.\n");
_getch();
return 0;
}
_cputs("The new process is created.\n");
// ждем завершения созданного процесса
WaitForSingleObject(piApp.hProcess, INFINITE);
// закрываем дескрипторы этого процесса в текущем процессе
CloseHandle(piApp.hThread);
CloseHandle(piApp.hProcess);
return 0;
2
2
}
В этой программе перед запуском консольного процесса Primer.exe все поля структуры si
типа STARTUPINFO должны заполняться нулями. Это делается с помощью функции
VOID ZeroMemory( PVOID Destination, SIZE_T Length);
В этом случае вид главного окна запускаемого приложения определяется по умолчанию
ОС Windows. Далее в в параметре dwCreationFlags устанавливается флаг
CREATE_NEW_CONSOLE. Это говорит системе, что для запускаемого процесса должна
быть создана новая консоль. Если этот параметр равен NULL, то новая консоль для запускаемого процесса не создается и весь консольный вывод нового процесса направляется в
консоль родительского процесса.
Имя нового процесса можно задать через командную строку, при этом имя может не содержать полного пути к exe-файлу. При использовании параметра lpCommandLine система для запуска нового процесса осуществляет поиск требуемого exe-файла в определенных директориях: каталог, из которого запущено приложение, текущий каталог родительского процесса, системный каталог Windows, каталог Windows, каталоги, перечисленные
в переменной PATH.
Завершение процессов
Процесс может завершить свою работу вызовом функции ExitProcess:
VOID ExitProcess(
UINT uExitCode //код возврата из процесса
}
При вызове функции ExitProcess завершаются все потоки процесса с кодом возврата, который является параметром этой функции. При выполнении система посылает динамическим библиотекам, которые загружены процессом, сообщение
DLL_PROCESS_DETACH, которое говорит о том, что динамическую библиотеку необходимо отсоединить от процесса, например,
#include <windows.h>
#include <iostream.h>
volatile UINT count;
void thread()
{
for (;;)
{
count++;
Sleep(100);
}
}
int main()
{
char c;
HANDLE
hThread;
DWORD IDThread;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread, NULL,
0, &IDThread);
if (hThread == NULL)
return GetLastError();
for (;;)
{
cout << "Input 'y' to display the count or any char to exit: ";
cin >> (char)c;
if (c == 'y')
cout << "count = " << count << endl;
else
2
3
ExitProcess(1);
}
}
Один процесс может быть завершен другим при помощи вызова функции TerminateProcess :
BOOL TerminateProcess(
HANDLE hProcess,
UINT uExitCode)
Если функция TerminateProcess выполнилась успешно, то она возвращает ненулевое значение. В противном случае возвращает FALSE. Функция TerminateProcess завершает
работу процесса, но не освобождает все ресурсы, принадлежащие этому процессу, так как
функция не посылает динамическим библиотекам, загруженным в процесс сообщение об
отсоединении от процесса. Пример использования функции: сначала создается программа
с бесконечным процессом-счетчиком (Primer2.exe) , а затем программу, которая запускает
бесконечный процесс и завершает по требованию пользователя:
#include <windows.h>
#include <iostream.h>
int count;
void main()
{
for ( ; ; )
{
count++;
Sleep(1000);
cout << "count = " << count << endl;
}
}
#include <windows.h>
#include <conio.h>
int main()
{
char lpszAppName[] = "имя_диска:\\путь_\\Primer2.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);
// создаем новый консольный процесс
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
_cputs("The new process is not created.\n");
_cputs("Check a name of the process.\n");
_cputs("Press any key to finish.\n");
_getch();
return 0;
}
_cputs("The new process is created.\n");
while (true)
{
char c;
_cputs("Input 't' to terminate the new console process: ");
c = _getch();
2
4
if (c == 't')
{
_cputs("t\n");
// завершаем новый процесс
TerminateProcess(pi.hProcess,1);
break;
}
}
// закрываем дескрипторы нового процесса в текущем процессе
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
Наследование дескрипторов
Свойство наследования объекта означает, что если наследуемый объект создан или открыт в некотором процессе, то к этому объекту будут иметь доступ все процессы, которые
создаются этим процессом, т.е. являются его потомками. Свойство наследования определяется его дескриптором. Для того, чтобы дочерний процесс имел доступ к наследуемому
объекту в родительском процессе, недостаточно просто сделать дескриптор этого объекта
наследуемым. Кроме того, нужно, во-первых, установить значение параметра bInheritHandles функции CreateProcess в TRUE, во-вторых, передать сам дескриптор дочернему
процессу. Наследуемый дескриптор передается системой дочернему процессу неявно и
поэтому он скрыт от программ, и поэтому он скрыт от программ, которые выполняются в
дочернем процессе, т.е. программа дочернего процесса должна явно знать этот дескриптор
и передать его этой программе должна программа родительского процесса. Дескриптор
можно передать как параметр, используя командную строку, например:
#include <windows.h>
#include <conio.h>
volatile int count;
void thread()
{
for (;;)
{
count++;
Sleep(500);
_cprintf ("count = %d\n", count);
}
}
int main()
{
char lpszComLine[80]; // для командной строки
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
HANDLE hThread;
DWORD IDThread;
_cputs("Press any key to start the count-thread.\n");
_getch();
// устанавливает атрибуты защиты потока
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
// защита по умолчанию
sa.bInheritHandle = TRUE;
// дескриптор потока наследуемый
// запускаем поток-счетчик
hThread = CreateThread(&sa, 0, (LPTHREAD_START_ROUTINE)thread, NULL, 0,
&IDThread);
2
5
if (hThread == NULL)
return GetLastError();
// устанавливаем атрибуты нового процесса
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);
// формируем командную строку
wsprintf(lpszComLine, "C:\\ConsoleProcess.exe %d", (int)hThread);
// запускаем новый консольный процесс
if (!CreateProcess(
NULL,
// имя процесса
lpszComLine, // адрес командной строки
NULL,
// атрибуты защиты процесса по умолчанию
NULL,
// атрибуты защиты первичного потока по умолчанию
TRUE,
// наследуемые дескрипторы текущего процесса
// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL,
// используем среду окружения процесса предка
NULL,
// текущий диск и каталог, как и в процессе предке
&si,
// вид главного окна - по умолчанию
&pi
// здесь будут дескрипторы и идентификаторы
// нового процесса и его первичного потока
)
)
{
_cputs("The new process is not created.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// закрываем дескрипторы нового процесса
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// ждем закрытия потока-счетчика
WaitForSingleObject(hThread, INFINITE);
_cputs("Press any key to exit.\n");
_getch();
// закрываем дескриптор потока
CloseHandle(hThread);
return 0;
}
Если дескриптор созданного объекта является ненаследуемым, а необходимо сделать его
наследуемым, то для решения этой проблемы используют функцию SetHandleInformation,
которая имеет следующий вид:
BOOL SetHandleInformation(
HANDLE hObject, //дескриптор объекта
DWORD dwMask, //флаги, которые изменяете
DWORD dwFlags ); //новые значения флагов
Для определения свойств дескриптора используется функция GetHandleInformation, которая имеет следующий вид:
BOOL GetHandleInformation(
HANDLE hObject, //дескриптор объекта
LPDWORD lpdwFlags //свойства дескриптора
);
В следующем примере показано изменение свойства наследования дескриптора:
#include <windows.h>
#include <conio.h>
2
6
volatile int count;
void thread()
{
for (;;)
{
count++;
Sleep(500);
_cprintf ("count = %d\n", count);
}
}
int main()
{
// имя нового процесса с пробелом
char lpszComLine[80]="C:\\ConsoleProcess.exe ";
// для символьного представления дескриптора
char lpszHandle[20];
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE hThread;
DWORD IDThread;
_cputs("Press any key to start the count-thread.\n");
_cputs("After terminating the thread press any key to exit.\n");
_getch();
// запускаем поток-счетчик
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread, NULL,
0, &IDThread);
if (hThread == NULL)
return GetLastError();
// делаем дескриптор потока наследуемым
if(!SetHandleInformation(
hThread,
// дескриптор потока
HANDLE_FLAG_INHERIT,
// изменяем наследование дескриптора
HANDLE_FLAG_INHERIT)) // делаем дескриптор наследуемым
{
_cputs("The inheritance is not changed.\n");
_cputs("Press any char to finish.\n");
_getch();
return GetLastError();
}
// устанавливаем атрибуты нового процесса
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);
// преобразуем дескриптор в символьную строку
_itoa((int)hThread,lpszHandle,10);
// создаем командную строку
strcat(lpszComLine,lpszHandle);
// запускаем новый консольный процесс
if (!CreateProcess(
NULL,
// имя процесса
lpszComLine, // адрес командной строки
NULL,
// атрибуты защиты процесса по умолчанию
NULL,
// атрибуты защиты первичного потока по умолчанию
TRUE,
// наследуемые дескрипторы текущего процесса
// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL,
// используем среду окружения процесса предка
2
7
NULL,
&si,
&pi
//
//
//
//
текущий диск и каталог, как и в процессе предке
вид главного окна - по умолчанию
здесь будут дескрипторы и идентификаторы
нового процесса и его первичного потока
)
)
{
_cputs("The new process is not created.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// закрываем дескрипторы нового процесса
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
_getch();
// закрываем дескриптор потока
CloseHandle(hThread);
return 0;
}
Иногда при передаче дескриптора из одного процесса в другой необходимо изменить не
только свойство наследования дескриптора, но и другие свойства этого дескриптора, которые управляют доступом к объекту. Для этого предназначена функция DuplicateHandle,
которая имеет следующий вид:
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle, //дескриптор процесса источника
HANDLE hSourceHandle, //исходный дескриптор
HANDLE hTargetProcessHandle, //дескриптор процесса приемника
LPHANDLE lpTargetHandle, //дубликат исходного дескриптора
DWORD dwDesiredAccess, //флаги доступа к объекту
BOOL bInheritHandle, //наследование дескриптора
DWORD dwOptions); дополнительные необязательные флаги)
Параметр dwDesiredAccess определяет возможные режимы доступа к объекту через дубликат исходного дескриптора, используя определенную комбинацию комбинацию флагов.
Параметр bInheritHandle устанавливает свойство наследования нового дескриптора. Если
его значение равно TRUE, то создаваемый дубликат исходного дескриптора является
наследуемым.
Для параметра dwOptions может быть установлена комбинация флагов DUPLICATE_CLOSE_SOURCE и DUPLICATE_SAME_ACCESS. Если установлен флаг DUPLICATE_CLOSE_SOURCE, то при любом своем завершении функция DuplicateHandle
закрывает исходный дескриптор. Если установлен флаг DUPLICATE_SAME_ACCESS, то
режимы доступа к объекту через дублированный дескриптор совпадают с режимами доступа к объекту через исходный дескриптор. Совместное использование этих флагов
обеспечивает выполнение двух указанных действий.
Псевдодескрипторы процессов
Иногда процессу требуется знать свой дескриптор, чтобы изменить какие-то свои характеристики. Для этого используется функция GetCurrentProcess, которая имеет следующий
вид:
HANDLE GetCurrentProcess(VOID);
и возвращает псевдодескриптор текущего процесса. Псевдодескриптор отличается от
настоящего дескриптора процесса тем, что он может использоваться только текущим процессом и не может наследоваться другими процессами. Псевдодескриптор процесса не
2
8
нужно закрывать после его использования. Из псевдодескриптора можно получить настоящий дескриптор процесса, продублировав его функцией DuplicateHandle.
Приоритеты потоков в Windows определяются относительно приоритета процесса, в контексте которого они выполняются. Приоритет процессов устанавливается при их создании
функцией CreateProcess, используя параметр dwCreationFlags. В этом параметре можно
установить один из следующих флагов:
Задание
№ 1. Создайте консольное приложение, которое запускает новый процесс, задавая имя
программы в командной строке. Задайте небольшую остановку (Sleep(1000)) и вывод сообщений.
№ 2. Запустите приведенные примеры наследования дескрипторов, устранив при необходимости ошибки (для имеющегося компилятора). Объясните механизм наследования дескрипторов.
№ 3. Создайте программу, которая использует функцию DuplicateHandle для разрешения
дочернему процессу завершить поток в родительском процессе. Приведите пример программы с использованием различных флагов.
Ход выполнения работы
№1. Самостоятельно, используя примеры.
№ 2 Самостоятельно, используя примеры
№3
Создайте приложение, которое будем запускать новое приложение как дочерний процесс:
#include <windows.h>
#include <conio.h>
int main(int argc, char *argv[])
{
HANDLE hThread;
char c;
// преобразуем символьное представление дескриптора в число
hThread = (HANDLE)atoi(argv[1]);
// ждем команды о завершении потока
while (true)
{
_cputs("Input 't' to terminate the thread: ");
c = _getch();
if (c == 't')
{
_cputs("t\n");
break;
}
}
// завершаем поток
TerminateThread(hThread, 0);
// закрываем дескриптор потока
CloseHandle(hThread);
_cputs("Press any key to exit.\n");
_getch();
2
9
return 0;
}
Откомпилируйте и сохраните, например, на Рабочем столе под именем ConsProcess.exe.
Теперь создайте приложение, в котором, запускается дочерний процесс, запускается новый поток в основном процессе и из дочернего процесса, останавливаем поток в основном проуессе.
#include <windows.h>
#include <conio.h>
volatile int count;
void thread()
{
for (;;)
{
count++;
Sleep(500);
_cprintf ("count = %d\n", count);
}
}
int main()
{
// имя нового процесса с пробелом
char lpszComLine[80]="C:\\Documents and Settings\\tec435\\Рабочий
стол\\ConsProcess.exe ";
// для символьного представления дескриптора
char lpszHandle[20];
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE hThread, hInheritThread;
DWORD IDThread;
_cputs("Press any key to start the count-thread.\n");
_cputs("After terminating the thread press any key to exit.\n");
_getch();
3
0
// запускаем поток-счетчик
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread, NULL,
0, &IDThread);
if (hThread == NULL)
return GetLastError();
// создаем наследуемый дубликат дескриптора потока
if(!DuplicateHandle(
GetCurrentProcess(), // дескриптор текущего процесса
hThread,
// исходный дескриптор потока
GetCurrentProcess(), // дескриптор текущего процесса
&hInheritThread,
// новый дескриптор потока
0,
// этот параметр игнорируется
TRUE,
// новый дескриптор наследуемый
DUPLICATE_SAME_ACCESS)) // доступ не изменяем
{
_cputs("The handle is not duplicated.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// устанавливаем атрибуты нового процесса
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);
// преобразуем наследуемый дескриптор в символьную строку
_itoa((int)hInheritThread,lpszHandle,10);
// создаем командную строку
strcat(lpszComLine,lpszHandle);
// запускаем новый консольный процесс
if (!CreateProcess(
NULL,
// имя процесса
lpszComLine, // адрес командной строки
NULL,
// атрибуты защиты процесса по умолчанию
NULL,
// атрибуты защиты первичного потока по умолчанию
TRUE,
// наследуемые дескрипторы текущего процесса
// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL,
// используем среду окружения процесса предка
NULL,
// текущий диск и каталог, как и в процессе предке
&si,
// вид главного окна - по умолчанию
&pi
// здесь будут дескрипторы и идентификаторы
// нового процесса и его первичного потока
)
)
{
_cputs("The new process is not created.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// закрываем дескрипторы нового процесса
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
_getch();
// закрываем дескриптор потока
CloseHandle(hThread);
return 0;
}
Откомпилтруйте, запустите на выполнение. Объясните каждый оператор программы,
параметры функции DuplicateHandle
3
1
Контрольные вопросы
1. Какие функции используются для создания нового процесса?
2. Какие параметры нужно задать для его создания нового процесса?
3. Что понимается под наследованием процесса?
4. Какие механизмы наследования используются в Windows NT5?
5. Как можно выполнить наследование процесса? Приведите пример программного
кода , реализующего наследование.
Литература
Основная
6. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
7. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
8. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
9. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
10.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.: ООО
«Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 3 (4 часа)
Тема: Синхронизация потоков и процессов
Цель: Изучить использование объектов синхронизации
Задание.
№ 1. Имеется программа, в которой два паллельно работающие потоки содержат не равные между собой элементы.Нужно изменить программу так, чтобы выполнялась синхронизация и в каждой строке выводились равные между собой числа. Для синхронизации
используйте критическую секцию.
#include <windows.h>
#include <iostream.h>
DWORD WINAPI thread(LPVOID)
{
int i,j;
for (j = 0; j < 10; ++j)
{
3
2
// выводим строку чисел j
for (i = 0; i < 10; ++i)
{
cout << j << ' ' << flush;
Sleep(17);
}
cout << endl;
}
return 0;
}
int main()
{
int i,j;
HANDLE hThread;
DWORD IDThread;
hThread=CreateThread(NULL, 0, thread, NULL, 0, &IDThread);
if (hThread == NULL)
return GetLastError();
for (j = 10; j < 20; ++j)
{
for (i = 0; i < 10; ++i)
{
// выводим строку чисел j
cout << j << ' ' << flush;
Sleep(17);
}
cout << endl;
}
// ждем, пока поток thread закончит свою работу
WaitForSingleObject(hThread, INFINITE);
return 0;
}
№
2.Создайте
консольное
приложение,
реализующее
использование
функции
WaitForMultipleObjects для ожидания завершения двух потоков.
3
3
№ 3. Измените имеющиеся программы, с целью синхронизации вывода. Первая программа запускает вторую программу, не создавая при этом новую консоль. После этого потоки из разных процессов начинают выводить числа в одну консоль. Из-за отсутствия синхронизации числа в одной строке могут быть из разных потоков. Для синхронизации используйте мьютекс.
#include <windows.h>
#include <iostream.h>
int main()
{
char lpszAppName[] = "C:\\ConsoleProcess.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// создаем новый консольный процесс
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
NULL, NULL, NULL, &si, &pi))
{
cout << "The new process is not created." << endl;
cout << "Press any key to exit." << endl;
cin.get();
return GetLastError();
}
// выводим на экран строки
for (int j = 0; j < 10; ++j)
{
for (int i = 0; i < 10; ++i)
{
cout << j << ' ' << flush;
Sleep(10);
}
cout << endl;
}
// ждем, пока дочерний процесс закончит работу
WaitForSingleObject(pi.hProcess, INFINITE);
// закрываем дескрипторы дочернего процесса в текущем процессе
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
/////////////
#include <windows.h>
#include <iostream.h>
int main()
{
int i,j;
3
4
for (j = 10; j < 20; ++j)
{
for (i = 0; i < 10; ++i)
{
cout << j << ' ' << flush;
Sleep(5);
}
cout << endl;
}
return 0;
}
№ 3. Создайте две программы. Первая программа - это родительский процесс, который
создает событие с автоматическим сбросом, а затем запускает дочерний процесс. После
этого родительский процесс ждет до тех пор, пока дочерний процесс не установит это событие в сигнальное состояние. Дождавшись этого, он завершает работу. Дочерний процесс открывает событие, созданное в родительском процессе. Затем, после каких-либо
действий, устанавливает событие в сигнальное состояние и завершает работу.
Контрольные вопросы
1. Объясните назначение блокирующих функций (interlocked functions).
2. Какие четыре типа блокирующих функций используются в Windows?
3. Что означает выражение «поток находится в тупике»?
4. Как выполняется классификация системных ресурсов?
5. Как обнаружить тупик?
6. Как восстановить заблокированный процесс?
Литература
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1. Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual
C++ 6.00 для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый
дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.М.: ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 4-1 (2 часа)
Тема: Программирование консольных приложений
Цель: Изучить использование функций для работы с окном консоли
Краткие теоретические сведения
3
5
Консолью называется интерфейс, который используется приложением для ввода/вывода
текстовой информации. Консольные приложения применяются главным образом в системном программировании для разработки различных сервисов.
Консоль состоит из одного входного буфера и одного или нескольких буферов экрана.
Входной буфер содержит информацию о событиях ввода. Каждое событие ввода описывается записью. Все записи упорядочены в очередь, которая хранится в буфере ввода. Буфер
экрана содержит информацию для вывода в окно приложения и является двумерным массивом, который содержит символы и данные о цвете. Консоль обеспечивает два уровня
ввода/вывода текстовой информации: высокий и низкий. Функции высокого уровня обеспечивают ввод/вывод символов с консоли, игнорируя остальные события. Функции низкого уровня обеспечивают обработку всех событий, связанных с консольным приложением.
Входной буфер консоли содержит очередь записей, которые описывают события ввода.
События ввода подразделяются на следующие категории:
 ввод с клавиатуры;
 ввод с мыши;
 изменение размеров окна;
 изменение фокуса ввода;
 события, связанные с меню.
События, связанные с фокусом ввода и меню, обрабатываются системой и должны игнорироваться приложением. Каждому событию ввода в очереди сообщений соответствует
запись типа INPUT_RECORD, которая имеет следующую структуру:
typedef struct _INPUT _RECORD {
WORD EventType;
union {
KEY_EVENT_RECORD
KeyEvent;
MOUSE_EVENT_RECORD
MouseEvent;
WINDOW_BUFFER_SIZE_RECORD
WindowBufferSizeEvent;
MENU_EVENT_RECORD
MenuEvent;
FOCUS_EVENT_RECORD
FocusEvent;
} Event;
}
INPUT_RECORD;
где поле EventType определяет тип события и может принимать одно из следующих значений:
 KEY_EVENT ввод с клавиатуры;
 MOUSE_EVENT ввод с мыши;
 WINDOW_BUFFER_SIZE_EVENT изменение размеров окна;
 MENU_EVENT событие, связанное с меню;
 FOCUS_EVENT изменение фокуса ввода.
Объединение Event содержит запись только одного из перечисленных типов в зависимости от значения поля EventType.
Запись для ввода с клавиатуры имеет следующую структуру:
typedef struct _KEY_EVENT_RECORD {
BOOL bKeyDown;
WORD wRepeatCount;
WORD wVirtualKeyCode;
WORD wVirtualScanCode;
union {
WCHAR UnicodeChar;
CHAR
AsciiChar;
} uChar;
DWORD dwControlKeyState;
} KEY_EVENT_RECORD;
3
6
Поля этой структуры:
 значение поля bKeyDown равно TRUE, если клавиша нажата, в противном случае
значение этого поля равно FALSE;
 поле wRepeatCount содержит счетчик задержки при нажатии клавиши;
 поле wVirtualKeyCode содержит код клавиши, который не зависит от типа клавиатуры;
 поле wVirtualScanCode содержит код клавиши, который генерируется клавиатурой. Значение этого поля зависит от клавиатуры, так как клавиатуры разных производителей могут генерировать разные коды;
 объединение uChar содержит символ, который соответствует нажатой клавише.
Этот символ может быть представлен как в коде Unicode, так и в коде ASCII;
 поле dwControlKeyState содержит комбинацию флагов, которые описывают состояние управляющих клавиш. Эти флаги могут принимать следующие значения:
o CAPSLOCK_ON –
включен индикатор <Caps Lock>;
o ENHANGED_KEY дополнительные клавиши;
o LEFT_ALT_PRESSED нажата левая клавиша <Alt>;
o LEFT_CTRL_PRESSED - нажата левая клавиша <Ctrl>;
o NUMLOCK_ON включен индикатор <Num Lock>;
o RIGHT_ALT_PRESSED - нажата правая клавиша <Alt>;
o RIGHT_CTRL_PRESSED- нажата правая клавиша <Ctrl>;
o SCROLLLOCK_ONвключен индикатор <Scroll Lock>;
o SHIFT_PRESSED нажата клавиша <Shift>.
Запись для ввода с мыши имеет следующую структуру:
typedef struct _MOUSE_EVENT_RECORD{
COORD dwMousePosition;
DWORD dwButtonState;
DWORD dwControlKeyState;
DWORD dwEventFlags;
} MOUSE_EVENT_RECORD;
поля структуры имеют следующее назначение:
 поле dwMousePosition определяет координаты курсора относительно буфера экрана;
 поле dwButtonState –содержит флаги, которые определяют состояние кнопок мыши. Эти флаги описываются следующими константами:
o FROM_LEFT_1ST_BUTTON_PRESSED –нажата самая левая кнопка мыши;
o RIGHTMOST_BUTTON_PRESSED-нажата самая правая кнопка мыши;
o FROM_LEFT_2ND_BUTTON_PRESSED-нажата вторая слева кнопка мыши;
o FROM_LEFT_3RD_BUTTON_PRESSED- нажата третья слева кнопка мыши
o FROM_LEFT_4TH_BUTTON_PRESSED- нажата четвертая слева кнопка
мыши;
 поле dwControlKeyState определяет состояние управляющих клавиш и может принимать те же значения , что и соответствующее поле в записи
KEY_EVENT_RECORD;
 поле dwEventFlags отмечает тип события и может принимать одно из следующих
значений:
o 0-кнопка мыши нажата или отпущена;
o DOUBLE_CLICK - кнопка мыши нажата второй раз, первое нажатие отмечается 0;
o MOUSE_MOVED – изменение позиции мыши;
o MOUSE_WHEELED – крутится колесо мыши.
3
7
Записи, описывающие события, связанные с изменениями размеров окна, имеют следующую структуру:
typedef struct _WINDOW_BUFFER_SIZE_RECORD {
COODR dwSize;
} WINDOW_BUFFER_SIZE_RECORD;
где поле dwSize определяет новый размер буфера экрана в символах.
Буфер экрана является двумерным массивом, элементы которого представляют собой
записи типа:
typedef struct _CHAR_INFO{
union {
WCHAR UnicodeChar;
CHAR AsciiChar;
} Char;
DWORD Attributes;
} CHAR_INFO, *PCHAR_INFO;
где объединение Char содержит символ, представленный в коде Unicode или ASCII, а поле
Attributes определяет цвет фона и цвет текста, которыми выводятся символы на экран.
Это значение может быть равно 0, что обозначает фон - черный, а цвет –белый. Возможно также использование любой комбинации следующих констант:
 BACKGROUND_BLUE фон синий;
 BACKGROUND_GREEN фон зеленый;
 BACKGROUND_RED фон красный;
 BACKGROUND_INTENSITY - фон яркий;
 FOREGROUND_BLUE –
текст синий;
 FOREGROUND_GREEN текст зеленый;
 FOREGROUND_RED текст красный;
 FOREGROUND_INTENSITY текст яркий.
Создание консоли
Процесс может быть связан только с одной консолью. Новая консоль может создаваться:
1. При создании процесса CreateProcess нужно установить флаг CREATE_NEW_CONSOLE. Если консольный процесс создается из консольного приложения , указанный флаг не установлен, то новый процесс присоединяется к консоли родительского процесса.
2. Использованием функции
BOOL AllocConsole (VOID);
Эта функция возвращает ненулевое значение, если консоль создана успешно, и
FALSE - в противном случае.
В обоих случаях заголовок окна консоли, его параметры задаются следующими полями
структуры STARTUPINFO
 lpTitle -заголовок окна консоли;
 dwX, dwY –позиция левого угла окна консоли;
 dwXSize, dwYSize – размеры окна;
 dwXCountChars, dwYCountChars – размеры буфера экрана;
 dwFillAttributes – цвет фона и цвет текста;
 wShowWindow – способ отображения окна при запуске приложения
Все эти параметры используются при запуске процесса только в том случае, если в поле
dwFlags этой же структуры установлены следующие управляющие флаги:
 STARTF_USEPOSITION - использовать поля dwX, dwY;
 STARTF_USESIZE –использовать поля dwXSize, dwYSize ;
3
8



STARTF_USECOUNTCHARS - использовать поля dwXCountChars, dwYCountChars
STARTF_USEFILLATTRIBUTE- использовать поле dwFillAttributes;
STARTF_USESHOWWINDOW - использовать поле wShowWindow.
Освобождение консоли
Приложение освобождает консоль посредством вызова функции FreeConsole, которая
имеет следующий прототип
BOOL FreeConsole(VOID);
В случае успешного завершения эта функция возвращает ненулевое значение, а в противном случае - FALSE.
Стандартные дескрипторы ввода/вывода
При создании новой консоли система создает три дескриптора, которые обозначаются
STDIN, STDOUT, STDERR и называются соответственно стандартными дескрипторами ввода, вывода, и ошибки. Эти дескрипторы используются в функциях, предназначенных для работы с консолью. Дескриптор STDIN связывается с буфером ввода. Дескрипторы STDOUT и STDERR связываются с буфером экрана.
Значения стандартных дескрипторов ввода-вывода можно получить, используя функцию GetStdHandle, которая имеет следующий прототип:
HANDLE GetStdHandle(DWORD dwStdHandle);
где параметр dwStdHandle может принимать одно из следующих значений:
 STD_INPUT_HANDLE дескриптор стандартного ввода;
 STD_OUTPUT_HANDLE - дескриптор стандартного вывода;
 STD_ERROR_HANDLE дескриптор стандартной ошибки.
В случае успешного завершения эта функция возвращает требуемый дескриптор, а в
противном случае - значение INVALID_HANDLE_VALUE.
Установить значения стандартных дескрипторов ввода/вывода можно при помощи
функции SetStdHandle, которая имеет следующий прототип:
BOOL SetStdHandle(
DWORD dwStdHandle, //тип дескриптора
HANDLE hHandle ); //новое значение дескриптора
где параметр dwStdHandle принимает те же значения, что и в функции GetStdHandle,
а параметр hHandle равен новому значению для стандартного дескриптора. При
успешном завершении функция SetStdHandle возвращает ненулевое значение, а в противном –FALSE.
Получение дескриптора окна консоли
Дескриптор окна консоли можно получить, вызвав функцию GetConsoleWindow, которая имеет следующий прототип:
HWND GetConsoleWindow (VOID);
При успешном завершении функция возвращает дескриптор окна консоли, а в противном – NULL.
Пример использования этой функции:
#include <windows.h>
#include <stdio.h>
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
int main()
{
HWND hWindow = NULL;
HDC hDeviceContext;
// дескриптор окна
// контекст устройства
3
9
HPEN hPen;
HGDIOBJ hObject;
// дескриптор пера
// дескриптор GDI объекта
// получаем дескриптор окна
hWindow = GetConsoleWindow();
if (hWindow == NULL)
{
printf("Get console window failed.\n");
return 1;
}
else
printf("Cet console window is done.\n");
// получаем контекст устройства
hDeviceContext = GetDC(hWindow);
// создаем перо
hPen = CreatePen(PS_SOLID, 10, RGB(0, 255, 0));
// устанавливает перо
hObject = SelectObject(hDeviceContext, hPen);
// рисуем линию
MoveToEx(hDeviceContext, 100, 100, NULL);
LineTo(hDeviceContext, 500, 100);
// востанавливает старый объект
SelectObject(hDeviceContext, hObject);
// освобождаем объекты
DeleteObject(hPen);
ReleaseDC(hWindow, hDeviceContext);
return 0;
}
Получение и изменение заголовка консоли
Для чтения заголовка окна консоли используется функция GetConsoleTitle, которая имеет
следующий прототип:
DWORD GetConsoleTitle(
LPTSTR lpConsoleTitle, // адрес буфера заголовка
DWORD nSize );
// размер буфера для заголовка в символах
В случае успеха эта функция возвращает длину строки заголовка в символах, а в
случае неудачи – 0.
Для установки заголовка окна консоли используется функция SetConsoleTitle, которая
имеет следующий прототип:
BOOL SetConsoleTitle(
LPCTSTR lpConsoleTitle);
//указатель на строку с заголовком
В случае успеха эта функция возвращает ненулевое значение, а в случае неудачи –
FALSE.
Например, для чтения заголовка:
char ConsoleTitleBuffer[512];
DWORD dwBufferSize = 512;
DWORD dwTitleSize;
// указатель на буфер с заголовком
// размер буфера для заголовка
// длина заголовка
// читаем заголовок консоли
dwTitleSize = GetConsoleTitle(ConsoleTitleBuffer, dwBufferSize);
Пример, для нового заголовка:
cout << "Input new title: ";
cin.getline(ConsoleTitleBuffer, 80);
4
0
// устанавливаем новый заголовок консоли
if (!SetConsoleTitle(ConsoleTitleBuffer))
//выводится сообщение
Определение максимального размера окна
Максимальный размер окна консоли можно определить, вызвав функцию GetLargestConsoleWindowSize, которая имеет следующий прототип:
COORD GetLargestConsoleWindowSize(
HANDLE hConsoleOutput );
//дескриптор буфера обмена
В случае успеха эта функция возвращает значения типа структуры
typedef struct _COORD {
SHORT X,
SHORT Y,
} COORD;
Поле X содержит максимальное количество столбцов, а поле Y –максимальное количество строк окна консоли в символах. X и Y зависят от текущего размера шрифта и величины экрана. В случае неудачи функция GetLargestConsoleWindowSize возвращает в полях структуры COORD нули.
Установка координат окна
Установить окно консоли относительно буфера экрана можно вызовом функции SetConsoleWindowInfo, которая имеет следующий прототип:
BOOL SetConsoleWindowInfo(
HANDLE hConsoleOutput, //дескриптор буфера экрана
BOOL bAbsolute,
//тип координат
CONST SMALL_RECT * lpConsoleWindow
//углы окна
);
Параметры этой функции могут принимать следующие значения:
 параметр hConsoleOutput должен содержать дескриптор буфера экрана, который
должен быть открыт в режиме GENERIC_WRITE;
 в параметре bAbsolute может быть установлено значение FALSE или TRUE. Если
значение этого параметра равно FALSE, то поля структуры SMALL_RECT определяют сдвиг буфера экрана относительно левого верхнего и правого нижнего углов
текущего окна консоли. Если же значение параметра bAbsolute равно TRUE, то
поля структуры SMALL_RECT задают абсолютное положение левого верхнего и
правого нижнего углов окна консоли относительно буфера экрана;
 для задания левого верхнего и правого нижнего углов окна используются поля
структуры SMALL_RECT, которая имеет следующий тип:
typedef struct _SMALL_RECT {
SHORT Left;
//x –координата левого верхнего угла окна консоли
SHORT Top;
//y- координата левого верхнего угла окна консоли
SHORT Right;
//x -координата правого нижнего угла окна консоли
SHORT Bottom;
//y- координата правого нижнего угла окна консоли
} SMALL_RECT;
В случае успеха функция SetConsoleWindowInfo возвращает ненулевое значение, а в
противном случае – FALSE.
Создание и активация буфера экрана
Буфер экрана может быть создан вызовом функции CreateConsoleScreenBuffer, которая
имеет следующий прототип:
HANDLE CreateConsoleScreenBuffer (
DWORD dwDesireAccess, //режимы доступа
DWORD dwShareMode,
//режимы разделения доступа
4
1
CONST SECURITY_ATTRIBUTES *lpSecurityAttributes, //атрибуты защиты
DWORD dwFlags,
//тип буфера экрана
LPVOID lpScreenBufferData //зарезервировано
);
В случае успешного завершения эта функция возвращает дескриптор нового буфера
экрана, а в случае неудачи значение INVALID_HANDLE_VALUE.
Параметры этой функции имеют следующее значение:
 В параметре dwDesireAccess задаются флаги, которые определяют способ доступа к буферу экрана. Этот параметр может принимать любую комбинацию
следующих значений:
o GENERIC_READ – процессу разрешается чтение данных из буфера
экрана;
o GENERIC_WRITE –процессу разрешается запись в буфер экрана.
 Параметр dwShareMode определяет, может ли буфер экрана использоваться несколькими процессами одновременно. Если этот параметр равен 0, то создаваемый буфер экрана не может использоваться несколькими процессами одновременно. Кроме того, этот параметр может принимать любую комбинацию следующих значений:
o FILE_SHARE_READ –буфер экрана допускает совместное чтение;
o FILE_SHARE_WRITE –буфер экрана допускает совместную запись.
 Параметр lpSecurityAttributes задает атрибуты защиты. По умолчанию –NULL
 Параметр dwFlags задает тип буфера экрана и может принимать только одно
значение CONSOLE_TEXTMODE_BUFFER
 Параметр lpScreenBufferData зарезервирован для дальнейшего использования
и поэтому должен быть установлен в NULL
После создания буфер экрана содержит пробелы, а курсор установлен в позицию с координатами (0, 0). Чтобы сделать буфер активным, т.е. выводить его содержимое на экран,
нужно вызвать функцию SetConsoleActiveScreenBuffer, которая имеет следующий прототип :
BOOL SetConsoleActiveScreenBuffer ( HANDLE hConsoleOutput);
При успешном завершении функция возвращает ненулевое значение, а в противном –
FALSE.
Пример использования функций CreateConsoleScreenBuffer и SetConsoleActiveScreenBuffer. В этом примере также используется функция WriteConsole для вывода в новый
буфер экрана:
#include <windows.h>
#include <conio.h>
int main()
{
HANDLE hStdOutOld, hStdOutNew; // дескрипторы буфера экрана
DWORD dwWritten;
// для количества выведенных символов
// создаем буфер экрана
hStdOutNew = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, // чтение и запись
0,
// не разделяемый
NULL,
// защита по умолчанию
CONSOLE_TEXTMODE_BUFFER,
// текстовый режим
NULL); // не используется
4
2
if (hStdOutNew == INVALID_HANDLE_VALUE)
{
_cputs("Create console screen buffer failed.\n");
return GetLastError();
}
// сохраняем старый буфер экрана
hStdOutOld = GetStdHandle(STD_OUTPUT_HANDLE);
// ждем команду на переход к новому буферу экрана
_cputs("Press any key to set new screen buffer active.\n");
_getch();
// делаем активным новый буфер экрана
if (!SetConsoleActiveScreenBuffer(hStdOutNew))
{
_cputs("Set new console active screen buffer failed.\n");
return GetLastError();
}
// выводим текст в новый буфер экрана
char text[] = "This is a new screen buffer.";
if (!WriteConsole(
hStdOutNew, // дескриптор буфера экрана
text,
// символы, которые выводим
sizeof(text), // длина текста
&dwWritten, // количество выведенных символов
NULL))
// не используется
_cputs("Write console output character failed.\n");
// выводим сообщение о вводе символа
char str[] = "\nPress any key to set old screen buffer.";
if (!WriteConsole(
hStdOutNew, // дескриптор буфера экрана
str,
// символы, которые выводим
sizeof(str), // длина текста
&dwWritten, // количество выведенных символов
NULL))
// не используется
_cputs("Write console output character failed.\n");
_getch();
// восстанавливаем старый буфер экрана
if (!SetConsoleActiveScreenBuffer(hStdOutOld))
{
_cputs("Set old console active screen buffer failed.\n");
return GetLastError();
}
// пишем в старый буфер экрана
_cputs("This is an old console screen buffer.\n");
// закрываем новый буфер экрана
CloseHandle(hStdOutNew);
// ждем команду на завершение программы
4
3
_cputs("Press any key to finish.\n");
_getch();
return 0;
}
Определение и установка параметров буфера экрана
Параметры буфера экрана можно определить с помощью функции CetConsoleScreenBufferInfo, которая имеет следующий прототип:
BOOL GetConsoleScreenBufferInfo (
HANDLE hConsoleOutput, //дескриптор буфера экрана
PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
//указатель на строку параметров буфера экрана
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
При успешном завершении функция CetConsoleScreenBufferInfo возвращает в параметре lpConsoleScreenBufferInfo указатель на структуру следующего типа:
typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
COORD dwSize;
//размер буфера экрана в символах (столбцы, строки)
COORD dwCursorPosition;
// координаты курсора в символах
WORD wAttributes;
//цвет фона и цвет текста
SMALL_RECT SrWindow;
//левый верхний и правый нижний углы окна
//относительно буфера экрана
COORD dwMaximumWindowSize; //максимальный размер окна
} CONSOLE_SCREEN_BUFFER_INFO;
Размер буфера экрана можно изменить, вызвав функцию SetConsoleScreenBufferSize,
которая имеет следующий прототип:
BOOL SetConsoleScreenBufferSize (
HANDLE hConsoleOutput, //дескриптор буфера экрана
COORD dwSize
//новый размер буфера экрана
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
Размер буфера экрана задается в символах и не может быть меньше размера окна консоли. Минимальные размеры буфера экрана также ограничены системой и зависят от
размера используемого шрифта и системных метрик SM_CXMIN и SM_CYMIN.
Функции для работы с курсором
Информацию о положении и видимости курсора можно получить, используя функцию
GetConsoleCursorInfo, которая имеет следующий прототип:
BOOL GetConsoleCursorInfo (
HANDLE hConsoleOutput,
//дескриптор буфера обмена
PCONSOLE_CURSOR_INFO lpConsoleCursorInfo //информация о курсоре
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
При успешном завершении функция возвращает в структуре типа CONSOLE_CURSOR_INFO, адрес структуры задается параметром lpConsoleCursorInfo,
информацию о курсоре. Эта структура имеет следующий формат:
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
4
4
Поле dwSize изменяется от 1 до 100 и определяет размер курсора в процентах от размера клетки для символа, а поле bVisible определяет видимость курсора. Если значение поля bVisible равно TRUE, то курсор видим, в противном случае – невидим.
Размер и видимость курсора устанавливается функцией SetConsoleCursorInfo, которая
имеет следующий прототип:
BOOL SetConsoleCursorInfo (
HANDLE hConsoleOutput, //дескриптор буфера экрана
CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo //информация о курсоре
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
При этом нужные значения размера и видимости курсора передаются через параметр
lpConsoleCursorInfo, который указывает на структуру типа
CONSOLE_CURSOR_INFO, содержащую эти значения.
Позиция курсора в буфере экрана устанавливается функцией SetConsoleCursorPosition,
которая имеет следующий прототип:
BOOL SetConsoleCursorPosition (
HANDLE hConsoleOutput, //дескриптор буфера экрана
COORD dwCursorPosition //новая позиция курсора
);
Например, в следующем примере демонстрируется использование функции SetConsoleCursorPosition :
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
char c;
HANDLE hStdOut; // дескриптор стандартного вывода
COORD coord;
// для позиции курсора
// читаем дескриптор стандартного вывода
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
cout << "Input new cursor position." << endl;
cout << "X = ";
cin >> coord.X;
cout << "Y = ";
cin >> coord.Y;
// установить курсор в новую позицию
if (!SetConsoleCursorPosition(hStdOut, coord))
{
cout << "Set cursor position failed." << endl;
return GetLastError();
}
cout << "This is a new position." << endl;
cout << "Input any char to exit: ";
cin >> c;
return 0;
}
4
5
Чтение и установка атрибутов консоли
Для установки атрибутов консоли используется функция FillConsoleOutputAttribute,
которая имеет следующий прототип:
BOOL FillConsoleOutputAttribute (
HANDLE hConsoleOutput, //дескриптор буфера экрана
WORD wAttribute,
//цвет фона и цвет текста
DWORD nLength,
//количество заполняемых клеток
COORD dwWriteCoord,
//координаты первой клетки
LPDWORD lpNumberOfAttrsWritten
//количество заполненных клеток
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
Функция FillConsoleOutputAttribute заполняет клетки экрана, количество которых задано параметром nLength, атрибутами которые заданы параметром wAttribute. Параметр dwWriteCoord задает координаты первой заполняемой клетки, а параметр
lpNumberOfAttrsWritten должен указывать на переменную типа DWORD, в которую
функция FillConsoleOutputAttribute помещает количество заполненных клеток.
#include <cstdlib>
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, char *argv[])
{
char c;
HANDLE hStdOut; // дескриптор стандартного вывода
WORD wAttribute; // цвет фона и текста
DWORD dwLength; // количество заполняемых клеток
DWORD dwWritten; // для количества заполненных клеток
COORD coord;
// координаты первой клетки
CONSOLE_SCREEN_BUFFER_INFO csbi; // для параметров буфера экрана
cout << "In order to fill console attributes, input any char: ";
cin >> c;
// читаем стандартный дескриптор вывода
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut == INVALID_HANDLE_VALUE)
{
cout << "Get standard handle failed." << endl;
return GetLastError();
}
// читаем параметры выходного буфера
if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
{
cout << "Console screen buffer info failed." << endl;
return GetLastError();
}
// вычисляем размера буфера в символах
4
6
dwLength = csbi.dwSize.X * csbi.dwSize.Y;
// заполнение буфера с первой клетки
coord.X = 0;
coord.Y = 0;
// цвет фона –синий , цвет символов - желтый
wAttribute = BACKGROUND_BLUE | BACKGROUND_INTENSITY |
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
// заполнение буфера атрибутами
if (!FillConsoleOutputAttribute(
hStdOut, //стандартный дескриптор вывода
wAttribute, // цвет фона и текста
dwLength, // длина буфера в символах
coord,
// индекс первой клетки
&dwWritten)) // кол-во заполненных клеток
{
cout << "Fill console output attribute failed." << endl;
return GetLastError();
}
cout << "The fill attributes was changed." << endl;
// return 0;
system("PAUSE");
return EXIT_SUCCESS;
}
Для того чтобы установить атрибуты символов, которые пишутся в буфер экрана
функциями WriteFile и WriteConsole, а также отображаются на экране при чтении
функциями ReadFile и ReadConsole, используется функция SetConsoleTextAttributes,
которая имеет следующий прототип:
BOOL SetConsoleTextAttributes (
HANDLE hConsoleOutput, //дескриптор буфера экрана
WORD wAttribute
//цвет фона и цвет текста
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
Параметр wAttribute содержит новые цвета фона и текста.
Для установки атрибутов в последовательные клетки буфера экрана используется
функция WriteConsoleOutputAttribute, которая имеет следующий прототип:
BOOL WriteConsoleOutputAttribute (
HANDLE hConsoleOutput,
//дескриптор буфера экрана
CONST WORD * lpAttribute,
//указатель на атрибуты
DWORD nLength,
//количество заполняемых клеток
COORD dwWriteCoord,
//координаты первой клетки
LPDWORD lpNumberOfAttrsWritten
//кол-во заполненных клеток
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
Все параметры этой функции, кроме lpAttribute, имеют тот же смысл, что и соответствующие параметры функции SetConsoleTextAttributes. Параметр lpAttribute указывает на массив атрибутов, которые будут заноситься в последовательные клетки буфе-
4
7
ра экрана. Функция WriteConsoleOutputAttribute позволяет заполнять последовательные клетки буфера экрана не одним, а разными атрибутами.
Для чтения атрибутов текста буфера экрана из последовательных ячеек используется
функция ReadConsoleOutputAttribute, которая имеет следующий прототип:
BOOL ReadConsoleOutputAttribute (
HANDLE hConsoleOutput, // дескриптор буфера экрана
LPWORD lpAttribute,
//указатель на атрибуты
DWORD nLength,
//количество заполняемых клеток
COORD dwWriteCoord,
//координаты первой клетки
LPDWORD lpNumberOfAttrsRead // кол-во заполненных клеток
);
В случае успеха функция возвращает ненулевое значение, а в случае неудачи – FALSE.
Назначение параметров hConsoleOutput и dwWriteCoord совпадают с назначением параметров функции WriteConsoleOutputAttribute. Параметр lpAttribute указывает на область памяти, в которую будут читаться атрибуты. Параметр nLength должен содержать количество клеток, из которых будут читаться атрибуты, а параметр lpNumberOfAttrsRead должен указывать на область памяти, в которую функция поместит количество прочитанных клеток.
Задание
№ 1. Примеры программ, приведенные в разделе “Краткие теоретические сведения”
откомпилируйте, запустите на выполнение, объясните использование функций, использующихся в этих программах.
№ 2. Создайте приложение, в котором устанавливаются значения структуры
STARTUPINFO, а затем с этими параметрами загружается дочерний консольный процесс. Задайте, например, позицию левого угла консоли 100, 200; размеры буфера экрана по горизонтали и вертикали по 100; цвет букв зеленый.
№ 3. Создайте приложение, в котором демонстрируется создание новой консоли при
помощи функции AllocConsole
№ 4. Создайте консольное приложение, в котором считывается строка заголовка, а затем устанавливается новый заголовок, а также определяются максимальные размеры
окна, определяются абсолютные размеры окна консоли и устанавливаются относительные размеры окна консоли.
№ 5. Создайте приложение, в котором читается стандартный дескриптор вывода, затем
читаются параметры буфера экрана и выводятся на консоль. Затем устанавливаются
новые размеры буфера экрана.
№ 6. Создайте приложение, в котором используются функции SetConsoleCursorInfo и
GetConsoleCursorInfo для чтения и установки параметров курсора.
№ 7. Создайте приложение, в котором используются функции WriteConsoleOutputAttribute и ReadConsoleOutputAttribute для установки и чтения атрибутов текста консоли
из последовательных клеток.
Контрольные вопросы
1. Что такое консоль? И что она представляет собой?
2. Как можно создать новую консоль?
3. Какие функции позволяют прочитать заголовок окна консоли и установить новый?
4. Как определить максимальный размер окна консоли?
5. Какие функции используются для работы с курсором?
Литература
Основная
4
8
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1. Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual
C++ 6.00 для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый
дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2.
Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.М.: ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 4-2 (2 часа)
Тема: Ввод и вывод на консоль
Цель: Изучить использование функций ввода и вывода на консоль
Краткие теоретические сведения
Ввод и вывод высокого уровня
Для чтения строки символов из входного буфера консоли экрана используется функция
ReadConsole, которая имеет следующий прототип:
BOOL ReadConsole (
HANDLE
hConsoleInput,
//дескриптор буфера экрана
LPVOID
lpBuffer,
//массив для ввода символов
DWORD
nNumberOfCharsToRead, //количество читаемых символов
LPDWORD lpNumberOfCharsRead,
//количество прочитанных символов
LPVOID
lpReserved
//зарезервировано
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – FALSE. Последний параметр всегда должен быть установлен в NULL. Функция
ReadConsole вводит символы последовательно друг за другом, при этом курсор передвигается в следующую свободную позицию. Если включен режим отображения введенных
символов, то при вводе символы отображаются на экране. Кроме того, в процессе ввода
символов из входного буфера консоли эта функция игнорирует все события ввода, которые отличаются от ввода символа.
Для записи строки символов в буфер экрана используется функция WriteConsole, которая
имеет следующий прототип:
BOOL WriteConsole (
HANDLE hConsoleOutput, //дескриптор буфера экрана
CONST VOID * lpBuffer, //массив с символами для вывода
DWORD nNumberOfCharsToWrite,
//кол-во записываемых символов
LPDWORD lpNumberOfCharsWritten,
//кол-во записанных символов
LPVOID lpReserved
//зарезервировано
);
4
9
Пример использования функций ReadConsole и WriteConsole:
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hStdOut, hStdIn;
//
DWORD dwWritten, dwRead;
//
char buffer[80];
//
char str[] = "Stroka for Input
char c;
дескрипторы консоли
для количества символов
для ввода символов
:";
// читаем дескрипторы консоли
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (hStdOut == INVALID_HANDLE_VALUE || hStdIn == INVALID_HANDLE_VALUE)
{
cout << "Get standard handle failed." << endl;
return GetLastError();
}
// выводим сообщения о вводе строки
if(!WriteConsole(hStdOut, &str, sizeof(str), &dwWritten, NULL))
{
cout << "Write console failed." << endl;
return GetLastError();
}
// вводим строку
if(!ReadConsole(hStdIn, &buffer, sizeof(buffer), &dwRead, NULL))
{
cout << "Read console failed." << endl;
return GetLastError();
}
// ждем команду на завершение работы
cout << "Input any char to exit: ";
cin >> c;
return 0;
}
Ввод и вывод на консоль при помощи функций ReadFile и WriteFile выполняется почти
так, как и функциями ReadConsole и WriteConsole. Отличие в том, что последний параметр в функциях ReadFile и WriteFile указывает на синхронный и асинхронный ввод или
вывод. Например, фрагменты кода, использующие функции ReadFile и WriteFile
// вводим строку с клавиатуры и дублируем её на экран
if (!ReadFile(
hStdIn, // дескриптор стандартного ввода
chBuffer, // буфер для чтения
80,
// длина буфера
&cRead, // количество прочитанных байтов
NULL)) // синхронный ввод
{
MessageBox(NULL, "Write file failed", "Win32 API error",
MB_OK | MB_ICONINFORMATION);
return GetLastError();
}
// выводим сообщение о вводе строки
if (!WriteFile(
hStdOut,
// дескриптор стандартного вывода
5
0
lpszPrompt2, // строка, которую выводим
lstrlen(lpszPrompt2), // длина строки
&cWritten, // количество записанных байтов
NULL))
// синхронный вывод
{
MessageBox(NULL, "Write file failed", "Win32 API error",
MB_OK | MB_ICONINFORMATION);
return GetLastError();
}
Ввод низкого уровня
Функции ввода низкого уровня работают непосредственно с записями входного буфера
консоли. К ним относятся функции ReadConsoleInput, PeekConsoleInput, WriteConsoleInput, GetNumberOfConsoleInputEvents, FlushConsoleInputBuffer.
Для чтения записей из входного буфера используется функция ReadConsoleInput, которая
имеет следующий прототип:
BOOL ReadConsoleInput (
HANDLE hConsoleInput,
//дескриптор входного буфера консоли
PINPUT_RECORD lpBuffer,
//буфер данных
DWORD nLength,
//количество читаемых записей
LPDWORD lpNumberOfEventsRead
//количество прочитанных записей
)
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE.
Параметр hConsoleInput должен содержать дескриптор входного буфера консоли.
Параметр lpBuffer должен указывать на область памяти, в которую будут читаться записи
из входного буфера консоли;
Параметр nLength должен содержать количество записей, которые пользователь хочет
прочитать из входного буфера консоли.
Праметр lpNumberOfEventsRead -функция записывает в него количество прочитанных
записей из буфера консоли
Для чтения записей из входного буфера консоли, не удаляя их оттуда, используется функция PeekConsoleInput. Параметры этой функции полностью совпадают с параметрами
функции ReadConsoleInput().
Функция WriteConsoleInput предназначена для записи событий ввода во входной буфер
консоли. Эта функция имеет следующий прототип:
BOOL WriteConsoleInput (
HANDLE hConsoleInput,
//дескриптор входного буфера консоли
CONST INPUT_RECORD *lpBuffer,
//указатель на буфер с записью
DWORD nLength,
//количество записываемых записей
LPDWORD lpNumberOfEventsWritten
//количество записанных записей
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE
Параметры этой функции имеют следующее значение:
 Параметр hConsoleInput должен содержать дескриптор входного буфера консоли;
 Параметр lpBuffer должен указывать на область памяти, из которой будут записываться записи во входной буфер консоли.
 Параметр nLength должен содержать количество записей, которые пользователь
хочет записать во входной буфер консоли.
 По адресу, заданному параметром lpNumberOfEventsWritten, функция запишет
количество записей во входном буфере консоли.
5
1
Для чтения количества записей, находящихся во входном буфере консоли используется
GetNumberOfConsoleInputEvents, которая имеет следующий прототип:
BOOL GetNumberOfConsoleInputEvents (
HANDLE hConsoleInput,
//дескриптор входного буфера консоли
LPDWORD lpNumberOfEvents
//указатель на количество записей
};
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE. В случае успешного завершения в переменную адреса, заданную параметром lpNumberOfEvents, функция записывает количество записей, находящихся в буфере ввода консоли.
Для очистки буфера ввода консоли используется функция FlushConsoleInputBuffer, которая имеет следующий прототип:
BOOL FlushConsoleInputBuffer (
HANDLE hConsoleInput ); //дескриптор входного буфера консоли
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE.
Для определения количества кнопок у мыши используется функция GetNumberOfMouseButton, которая имеет следующий прототип:
BOOL GetNumberOfMouseButton (
LPDWORD lpNumberOfMouseButtons ); //количество кнопок у мыши
Вывод низкого уровня
Функции вывода низкого уровня работают непосредственно с элементами буфера экрана:
 Чтение и запись последовательности символов:
o ReadConsoleOutputCharacter – чтение последовательности символов из буфера экрана;
o WriteConsoleOutputCharacter – запись последовательности символов в буфер
экрана;
 Заполнение буфера экрана заданным символом:
o FillConsoleOutputCharacter – заполнение буфера экрана;
 Чтение и запись прямоугольных областей символов:
o ReadConsoleOutput - чтение прямоугольной области символов из буфера
экрана;
o WriteConsoleOutput – запись прямоугольной области символов в буфер
экрана.
Для ввода последовательности символов из буфера экрана используется функция ReadConsoleOutputCharacter, которая имеет следующий прототип:
BOOL ReadConsoleOutputCharacter (
HANDLE hConsoleOutput,
//дескриптор буфера экрана
LPTSTR lpCharacter,
//указатель на буфер с символами
COORD dwReadCoord,
//количество читаемых символов
LPDWORD lpNumberOfCharsRead//количество прочитанных символов
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE.
Назначение параметров функции:
Пример использования ReadConsoleOutputCharacter:
#include <windows.h>
#include <cstdlib>
#include <iostream>
using namespace std;
5
2
int main()
{
HANDLE hConsoleOutput; // для дескриптора буфера экрана
CHAR lpBuffer[80]; // буфер для ввода
COORD dwReadCoord = {0, 0}; // координаты первого элемента в буфере
DWORD nNumberOfCharsRead; // количество прочитанных символов
// получаем дескриптор буфера экрана
hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsoleOutput == INVALID_HANDLE_VALUE)
{
cout << "Get standard handle failed." << endl;
return GetLastError();
}
// выводим те символы, которые будем читать
cout << 'P' << 'M' <<’I’< endl;
// читаем эти символы в буфер
if (!ReadConsoleOutputCharacter(
hConsoleOutput, // дескриптор буфера экрана
lpBuffer,
// буфер для ввода символов
3,
// количество читаемых символов
dwReadCoord, // координата первого символа
&nNumberOfCharsRead)) // количество прочитанных символов
{
cout << "Read consoleoutput character failed." << endl;
return GetLastError();
}
// выводим количество прочитанных символов и сами символы
cout << "Number of chars read: " << nNumberOfCharsRead << endl;
cout << "Read chars: " << lpBuffer[0] << lpBuffer[1] << lpBuffer[2] << endl;
// return 0;
system("PAUSE");
return EXIT_SUCCESS;
}
Для записи последовательности символов в буфер экрана используется функция
WriteConsoleOutputCharacter, которая имеет следующий прототип:
BOOL WriteConsoleOutputCharacter (
HANDLE hConsoleOutput,
//дескриптор буфера экрана
LPCTSTR lpCharacter,
//указатель на массив символов
DWORD nLength,
//количество записываемых символов
COORD dwWriteCoord,
//координаты первого символа в буфере экрана
LPDWORD lpNumberOfCharsWritten
//количество символов, записываемых в
//буфер экрана
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE. Эта функция записывает последовательность символов, на
которую указывает параметр lpCharacter, в буфер экрана, начиная с позиции, на которую
указывает параметр dwWriteCoord, а количество фактически записанных символов
функция возвращает по адресу, заданному параметром lpNumberOfCharsWritten.
5
3
Для заполнения всего или части буфера экрана определенным символом используется
функция FillConsoleOutputCharacter, которая имеет следующий прототип:
BOOL FillConsoleOutputCharacter (
HANDLE hConsoleOutput,
//дескриптор буфера экрана
TCHAR cCharacter,
//символ-заполнитель
DWORD nLength,
//длина заполняемой области
COORD dwWriteCoord,
//координаты первой клетки буфера экрана
LPDWORD lpNumberOfCharsWritten
//количество заполненных клеток
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE.
Функция ReadConsoleOutput предназначена для чтения прямоугольных областей символов и их атрибутов из буфера экрана. Она имеет следующий прототип:
BOOL ReadConsoleOutput (
HANDLE hConsoleOutput, //дескриптор буфера экрана
PCHAR_INFO lpBuffer,
//указатель на буфер с данными
COORD dwBufferSize,
//размер буфера с данными
COORD dwBufferCoord, //координаты для первого элемента в буфере
PSMALL_RECT lpReadRegion
//область ввода в буфере экрана
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE.
Назначение параметров:
Параметр hConsoleOutput должен содержать дескриптор буфера экрана;
Параметр lpBuffer должен указывать на область памяти, в которую будет читаться содержимое буфера экрана; причем эта область памяти рассматривается функцией как двумерный массив, элементами которого являются структуры типа CHAR_INFO. Размерность
этого массива задается параметром dwBufferSize. При этом поля X и Y структуры
COORD задают соответственно количество столбцов и строк этого массива.
Параметр lpReadRegion является указателем на структуру типа SMALL_RECT, которая
содержит координаты левого верхнего и правого нижнего углов прямоугольника в буфере
экрана, содержимое которого будет прочитано в область памяти, заданную параметром
lpBuffer.
Пример использования функции ReadConsoleOutput
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hConsoleOutput; // для дескриптора буфера экрана
CHAR_INFO lpBuffer[4];
// буфер для ввода
COORD dwBufferSize = {2, 2}; // размеры буфера
COORD dwBufferCoord = {0, 0}; // координаты первого элемента в буфере
SMALL_RECT ReadRegion = {0, 0, 1, 1}; // прямоугольник, который читаем
// выводим символы, которые будем читать
cout << 'a' << 'b' << endl << 'c' << 'd' << endl;
// получаем дескриптор ввода
hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsoleOutput == INVALID_HANDLE_VALUE)
{
cout << "Get standard handle failed." << endl;
5
4
return GetLastError();
}
// читаем символы
if (!ReadConsoleOutput(hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord,
&ReadRegion))
{
cout << "Read console input failed." << endl;
return GetLastError();
}
// распечатываем прочитанные символы
cout << "Read cells." << hex << endl;
for (int i = 0; i < 4; ++i)
cout << lpBuffer[i].Attributes << ' ' << lpBuffer[i].Char.AsciiChar << endl;
return 0;
// system("PAUSE");
// return EXIT_SUCCESS;
}
Для записи прямоугольных областей символов и их атрибутов в буфер экрана используется функция WriteConsoleOutput, которая имеет следующий прототип:
BOOL WriteConsoleOutput (
HANDLE hConsoleOutput,
//дескриптор буфера экрана
CONST CHAR_INFO *lpBuffer, //указатель на буфер с данными
COORD dwBufferSize,
//размер буфера с данными
COORD dwBufferCoord,
//координаты первого элемента в буфере
PSMALL_RECT lpWriteRegion
//область вывода в буфере экрана
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE. Функция записывает символы и их атрибуты из буфера, на
который указывает параметр lpBuffer, в область вывода буфера экрана, на которую указывает параметр lpWriteRegion.
Режимы ввода и вывода консоли
Функции ввода и вывода на консоль могут работать в нескольких режимах, которые устанавливаются функцией SetConsoleMode. Функция имеет следующий прототип:
BOOL SetConsoleMode (
HANDLE hConsoleHandle, //дескриптор ввода или вывода
DWORD dwMode
//режим ввода или вывода
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE.
Если параметр hConsoleHandle является дескриптором входного буфера, то режим ввода
который описывается параметром dwMode, может быть произвольной комбинацией следующих флагов:
 ENABLE_LINE_INPUT – функции ReadFile и ReadConsole читают символы до
тех пор, пока не встретят символ ENTER. В противном случае читается доступное
количество символов во входном буфере;
 ENABLE_ECHO_INPUT – символы, прочитанные функциями ReadFile и ReadConsole, выводятся на экран. Этот режим может использоваться только совместно с
режимом ENABLE_LINE_INPUT
 ENABLE_PROCESSED_INPUT – комбинация клавиш <Ctrl>+ <C> обрабатывается системой. Если этот режим Если этот режим используется совместно с режимом
5
5
ENABLE_LINE_INPUT, то управляющие символы \b, \r, \n также обрабатываются
системой.
 ENABLE_WINDOW_INPUT – изменение размеров окна обрабатывается приложением.
 ENABLE_MOUSE_INPUT – сообщения от мыши обрабатываются приложением.
Как видно из описания режимов, значения ENABLE_LINE_INPUT,
ENABLE_ECHO_INPUT, ENABLE_PROCESSED_INPUT влияют на работу функций ввода и вывода высокого уровня, а значения ENABLE_WINDOW_INPUT, ENABLE_MOUSE_INPUT – на работу функций низкого уровня ввода и вывода.
Если параметр hConsoleHandle является дескриптором буфера экрана, то режим ввода, который задается параметром dwMode, может быть произвольной комбинацией следующих
значений:
 ENABLE_PROCESSED_OUTPUT – функции WriteFile и WriteConsole обрабатывают во входном буфере управляющие символы: \n, \t, \b, \v, \a. Эти же действия
выполняются при выводе на экран ввода функций ReadFile и ReadConsole;
 ENABLE_WRAP_AT_EOL_OUTPUT – разрешает прокручивать буфер экранапри
выводе данных на консоль;
Для чтения установленных режимов ввода и вывода используется функция GetConsoleMode, которая имеет следующий прототип:
BOOL GetConsoleMode (
HANDLE hConsoleHandle, //входной или выходной дескриптор консоли
LPDWORD lpMode
//указатель на флаги режимов консоли
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи – значение FALSE. Если функция выполнилась успешно, то в двойном слове, на
которое ссылается параметр lpMode, будут установлены флаги режимов консоли.
Задание
№ 1. Создайте программу, в которой используются функции ввода и вывода на консоль
высокого уровня: WriteFile, ReadFile, WriteConsole, ReadConsole. Сделайте вывод, в чем
состоит отличие в использовании этих функций.
№ 2. Создайте программу, которая использует функции ввода низкого уровня консоли
ReadConsoleInput, PeekConsoleInput. В программе должно производиться чтение по одной
записи из входного буфера и распечатка их содержимого на экране.
№3. Создайте программу, которая использует функции ввода низкого уровня WriteConsoleInput, GetNumberOfConsoleInputEvents, FlushConsoleInputBuffer, GetNumberOfMouseButton. В программе символы записываются в буфер ввода, подсчитывается количество записей, затем буфер ввода очищается. Организуйте цикл обработки событий.
№ 4. Создайте программу, которая использует функции вывода низкого уровня ReadConsoleOutputCharacter, WriteConsoleOutputCharacter, FillConsoleOutputCharacter.
№ 5. Создайте программу, которая использует функцию FillConsoleOutputCharacter для
заполнения буфера экрана заданным символом, а затем для очистки буфера экрана.
№ 6. Создайте программу, в которой изменяются режимы входного буфера и буфера
экрана.
Контрольные вопросы
1. Какие функции осуществляют ввод и вывод высокого уровня на консоль?
2. Какие функции используются для ввода и вывода низкого уровня на консоль?
3. Чем отличается ввод-вывод высокого уровня от низкого?
4. Какие режимы определены для функций ввода-вывода консоли?
5. Чем отличается функция ReadConsole от ReadFile?
5
6
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.: ООО
«Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 5 (4 часа)
Тема: Обмен данными между параллельными процессами
Цель: Изучить использование функций Win32API для обмена данными между параллельными процессами.
Краткие теоретические сведения
Способы передачи данных между процессами
Под обменом данных между параллельными процессами понимается пересылка данных
от одного потока к другому потоку, предполагая, что эти потоки выполняются в контекстах разных процессов.
Если потоки выполняются в одном процессе, то для обмена данными между ними можно
использовать глобальные переменные и средства синхронизации потоков. Если потоки
выполняются в разных процессах –потоки не могут обращаться к общим переменным и
для обмена данными между ними существуют специальные средства ОС, т.е. для обмена
данными между процессами создается канал передачи данных. Канал данных включает
входной и выходной буферы памяти, потоки ядра ОС и общую память, доступ к которой
имеют оба потока ядра. В любом случае, обмен данными может быть организован только
через цепочку взаимодействующих потоков, которые обмениваются между собой данными через общую для них память. Чтобы организовать канал передачи данных между потоками программным путем, для этого надо потоки ядра ОС и общую память, используемую для обмена заменить файлом. Таким образом, обмен данными между процессами через общий файл представляет собой организацию простейшего канала передачи данных
между процессами. Иногда ОС может упростить доступ к разделяемому файлу, чтобы
ускорить обмен данными, например, ОС Windows, может проецировать файл на адресное
пространство процесса.
При обмене данными между параллельными процессами различают два способа передачи
данных:
потоком;
5
7
сообщением.
Связи между процессами
Перед передачей данных нужно установить связь между этими процессами на физическом
и логическом уровнях. По направлению передачи различают следующие виды связей:
полудуплексная связь, т.е. данные по этой связи могут передаваться только в одном
направлении;
дуплексная связь, т.е. данные по этой связи могут передаваться в обоих направлениях.
Рассмотрим только полудуплексные связи, определим возможные топологии связей:
2.1  1 -между собой связаны только два процесса;
3.1  N -один процесс связан с N процессами;
4.N  1 -каждый из N процессов связан с одним процессом;
5.N  M -каждый из N процессов связан с каждым из M процессов.
При разработке систем с обменом данными между процессами, сначала выбирается топология связей и направления передачи данных по этим связям. После этого в программах
реализуются выбранные связи с использованием специальных функций ОС. Эти функции
обеспечивает система передачи данных, которая является частью ядра ОС. При передаче
данных различают синхронный и асинхронный обмен данными. Если поток -отправитель,
отправив сообщение функцией send, блокируется до получения этого сообщения потоком-адресатом, то такое отправление сообщения называется синхронным. В противном
случае отправление сообщения называется асинхронным. Если поток-адресат, вызвавший
функцию receive, блокируется до тех пор пока не получит сообщение , то такое получение
сообщения называется синхронным. В противном случае получение сообщения называется асинхронным. Обмен сообщениями называется синхронным, если поток-отправитель
синхронно передает сообщения, а поток-адресат синхронно принимает эти сообщения. В
противном случае обмен сообщениями называется асинхронным.
Буферизация
Буфером называется вместимость связи между процессами, т.е. количество сообщений ,
которые могут одновременно пересылаться по этой связи. Различают три типа буферизации:
нулевая вместимость связи - в этом случае возможен только синхронный обмен
данными между процессами;
ограниченная вместимость связи (ограниченный буфер) — в этом случае, если буфер
полон, то отправитель сообщения должен ждать очистки буфера хотя бы от одного
сообщения
неограниченная вместимость связи (неограниченный буфер) -в этом случае
отправитель никогда не ждет при отправке сообщения.
Анонимные каналы
Анонимным каналом называется объект ядра операционной системы, который обеспечивает передачу данных между процессами, выполняющимися на одном компьютере. Процесс, который создает анонимный канал, называется сервером анонимного канала. Процессы, которые связываются с анонимным каналом, называются клиентами анонимного
канала. Анонимный -это такой канал передачи данных между процессами, который не
имеет имени.
Характеристики анонимных каналов:
2 не имеют имени;
3 полудуплексные;
4 передача данных потоком;
5 синхронный обмен данными;
6 возможность моделирования любой топологии связей.
По анонимному каналу можно передавать данные только в одном направлении, но каждый конец анонимного канала имеет свой дескриптор, который можно передать любому
5
8
дочернему процессу. Поэтому каждый процесс может как записывать данные в анонимный канал, так и читать данные оттуда.
Создание анонимных каналов
Анонимные каналы создаются процессом-сервером функцией :
BOOL CreatePipe (
PHANDLE hReadHandle, //дескриптор для чтения из канала
PHANDLE hWriteHandle, //дескриптор для записи в канал
LPSECURITY_ATTRIBUTES lpPipeAttributes,//атрибуты защиты
DWORD dwSize
//размер буфера в байтах
);
При удачном завершении функция CreatePipe возвращает ненулевое значение, а в случае
неудачи -FALSE.
В случае успешного завершения функция CreatePipe создает два дескриптора анонимного
канала -один для чтения данных из канала, а второй для записи данных в канал. Эти дескрипторы возвращаются в переменных, на которые указывают параметры hReadHandle
и hWriteHandle.
Параметр lpPipeAttributes определяет атрибуты защиты анонимного канала.
Параметр dwSize определяет размер буфера ввода/вывода анонимного канала. Можно
установить это значение в 0, тогда ОС сама выберет размер буфера по умолчанию.
Соединение клиентов с анонимным каналом
Так как анонимные каналы не имеют имени, то для соединения процесса-клиента с таким
каналом необходимо передать ему один из дескрипторов анонимного канала. При этом
передаваемый дескриптор должен быть наследуемым, а сам процесс-клиент должен быть
дочерним процессом процесса-сервера анонимного канала и наследовать наследуемые
дескрипторы процесса-сервера.
Наследование дескрипторов анонимного канала определяется значением поля
bInheritHandle в структуре типа SECURITY_ATTRIBUTES, на которую указывает параметр lpPipeAttributes. Если значение этого поля равно TRUE, то дескрипторы анонимного
канала создаются наследуемыми. Если процессу-клиенту передаются два дескриптора
анонимного канала, то они должны быть сделаны наследуемыми при создании анонимного канала процессом-сервером. Если процессу-клиенту передается только один из дескрипторов, то возможны следующие варианты:
1. создаются наследуемые дескрипторы анонимного канала, а затем тот дескриптор,
который не передается клиенту делается ненаследуемым;
2. создаются ненаследуемые дескрипторы анонимного канала, затем тот дескриптор,
который передается клиенту сделать наследуемым;
Для создания ненаследуемого и наследуемого дубликата исходного дескриптора используют функцию DuplicateHandle. После этого исходный дескриптор закрывается. В ОС
Windows 2000 можно также решить с помощью функции SetHandleInformation, которая
изменяет свойство наследования дескриптора.
Для того чтобы процесс-клиент наследовал дескрипторы анонимного канала он должен
быть создан функцией CreateProcess в процессе-сервере анонимного канала и параметр
bInheritHandle этой функции должен иметь значение TRUE.
Явная передача наследуемого дескриптора процессу-клиенту анонимного канала может
выполняться одним из следующих способов:
2. через командную строку;
3. через поля hStdInput, hStdOutput, hStdError структуры STARTUPINFO;
4. посредством сообщения WM_COPYDATA;
5. через файл
Обмен данными по анонимному каналу
Для записи данных в анонимный канал используется функция WriteFile, которая имеет
следующий прототип:
5
9
BOOL WriteFile (
HANDLE hAnonymousPipe,
//дескриптор анонимного канала
LPCVOID lpBuffer,
//буфер данных
DWORD dwNumberOfBytesToWrite,
//количество байтов для записи
LPDWORD lpNumberOfBytesWritten,
//количество записанных байтов
LPOVERLAPPED lpOverlapped
//асинхронный ввод
);
Функция WriteFile записывает в анонимный канал количество байт, заданных параметром dwNumberOfBytesToWrite, из буфера данных, на который указывает параметр
lpBuffer. Дескриптор вывода этого анонимного канала задается первым параметром функции WriteFile. Параметр lpOverlapped
предназначен для выполнения асинхронной операции вывода, но так как анонимные каналы поддерживают только синхронную передачу
данных, то он будет равен NULL.
Для чтения данных из анонимного канала используется функция ReadFile:
BOOL ReadFile (
HANDLE hAnonymousPipe,
//дескриптор анонимного канала
LPCVOID lpBuffer,
//буфер данных
DWORD dwNumberOfBytesToRead,
//количество байтов для чтения
LPDWORD lpNumberOfBytesRead,
//количество прочитанных байтов
LPOVERLAPPED lpOverlapped
//асинхронный вывод
);
Функция ReadFile читает из анонимного канала количество байт, заданных параметром
dwNumberOfBytesToRead, в буфер данных, на который указывает параметр lpBuffer.
Обмен данными по анонимному каналу осуществляется только в соответствии с назначением дескриптора этого канала. Дескриптор для записи в анонимный канал должен быть
параметром функции WriteFile, а дескриптор для чтения из анонимного канала должен
быть параметром функции ReadFile. Один и тот же процесс может как писать в анонимный канал, так и читать из него, должным образом используя дескрипторы этого канала.
Пример работы с анонимными каналами:
Процесс-сервер создает анонимный канал и дочерний процесс, которому передает один из
дескрипторов этого анонимного канала. Для передачи дескриптора используется командная строка и дочерний процесс будет клиентом анонимного канала. Клиенту передается
дескриптор для записи, серверу остается дескриптор для чтения.
////////////////////процесс-сервер
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <conio.h>
using namespace std;
int main()
{
char lpszComLine[80]; // для командной строки
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE hWritePipe, hReadPipe, hInheritWritePipe;
// создаем анонимный канал
if(!CreatePipe(
6
0
&hReadPipe, // дескриптор для чтения
&hWritePipe, // дескриптор для записи
NULL,
// атрибуты защиты по умолчанию, в этом случае
// дескрипторы hReadPipe и hWritePipe ненаследуемые
0))
// размер буфера по умолчанию
{
_cputs("Create pipe failed.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// делаем наследуемый дубликат дескриптора hWritePipe
if(!DuplicateHandle(
GetCurrentProcess(), // дескриптор текущего процесса
hWritePipe,
// исходный дескриптор канала
GetCurrentProcess(), // дескриптор текущего процесса
&hInheritWritePipe, // новый дескриптор канала
0,
// этот параметр игнорируется
TRUE,
// новый дескриптор наследуемый
DUPLICATE_SAME_ACCESS )) // доступ не изменяем
{
_cputs("Duplicate handle failed.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// закрываем ненужный дескриптор
CloseHandle(hWritePipe);
// устанавливаем атрибуты нового процесса
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// формируем командную строку
wsprintf(lpszComLine, "C:\\Documents and Settings\\tec435\\Рабочий стол\\1\\Project1.exe
%d", (int)hInheritWritePipe);
cout<<"descriptor "<<((int)hInheritWritePipe)<<endl;
// запускаем новый консольный процесс
if (!CreateProcess(
NULL, // имя процесса
lpszComLine, // командная строка
NULL, // атрибуты защиты процесса по умолчанию
NULL, // атрибуты защиты первичного потока по умолчанию
TRUE, // наследуемые дескрипторы текущего процесса
// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL, // используем среду окружения процесса предка
NULL, // текущий диск и каталог, как и в процессе предке
&si, // вид главного окна - по умолчанию
&pi
// здесь будут дескрипторы и идентификаторы
// нового процесса и его первичного потока
))
{
6
1
_cputs("Create process failed.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// закрываем дескрипторы нового процесса
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// закрываем ненужный дескриптор канала
CloseHandle(hInheritWritePipe);
// читаем из анонимного канала
for (int i = 0; i < 12; i++)
{
int nData;
DWORD dwBytesRead;
if (!ReadFile(
hReadPipe,
&nData,
sizeof(nData),
&dwBytesRead,
NULL))
{
_cputs("Read from the pipe failed.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
_cprintf("The number %d is read from the pipe.\n", nData);
}
// закрываем дескриптор канала
CloseHandle(hReadPipe);
_cputs("The process finished reading from the pipe.\n");
_cputs("Press any key to exit.\n");
_getch();
system("PAUSE");
return EXIT_SUCCESS;
}
///////////////////////////////////клиент
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <conio.h>
using namespace std;
int main(int argc, char *argv[])
{
HANDLE hWritePipe;
6
2
// преобразуем символьное представление дескриптора в число
hWritePipe = (HANDLE)atoi(argv[1]);
// ждем команды о начале записи в анонимный канал
_cputs("Press any key to start communication.\n");
_getch();
// пишем в анонимный канал
for (int i = 0; i < 12; i++)
{
DWORD dwBytesWritten;
if (!WriteFile(
hWritePipe,
&i,
sizeof(i),
&dwBytesWritten,
NULL))
{
_cputs("Write to file failed.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
_cprintf("The number %d is written to the pipe.\n", i);
Sleep(500);
}
// закрываем дескриптор канала
CloseHandle(hWritePipe);
_cputs("The process finished writing to the pipe.\n");
_cputs("Press any key to exit.\n");
_getch();
// return 0;
//}
system("PAUSE");
return EXIT_SUCCESS;
}
Анонимные каналы часто используются для перенаправления стандартного ввода/вывода.
Стандартные средства ввода/вывода, используемые в языке С++ поддерживаются функциями, определенными в заголовочных файлах stdio.h, iostream, conio.h
Функции, которые описаны в файле stdio.h, обеспечивают ввод/вывод в следующие стандартные файлы:
2. stdin- стандартный файл ввода;
3. stdout — стандартный файл вывода;
4. stderr — файл вывода сообщений об ошибках.
Функции и операторы, которые описаны в заголовке iostream, обеспечивают ввод/вывод в
стандартные потоки. в языке С++. При создании консоли с помощью функции
AllocConsole стандартные файлы и стандартные потоки ввода/вывода связываются с дескрипторами, которые заданы в полях hStdInput, hStdOutput HStdError структуры
STARTUPINFO. Поэтому если в эти поля будут записаны соответствующие дескрипторы
анонимного канала, то для передачи данных по анонимному каналу можно использовать
6
3
функции стандартного ввода/вывода. Такая процедура называется перенаправлением
стандартного ввода/вывода.
Функции ввода/вывода из заголовочного файла conio.h отличаются от функций ввода/вывода из заголовочного файла stdio.h стандартной библиотеки языка программирования С тем, что они всегда работают с консолью. Поэтому эти функции можно использовать для ввода/вывода на консоль даже в случае перенаправления стандартного ввода/выода.
Задание
№ 1. Создайте программу процесса-клиента анонимного канала, программу процессасервера анонимного канала. Дескрипторы анонимного канала передаются через командную строку. В программах должен быть реализован двусторонний обмен данными между
клиентом и сервером.
Для организации двустороннего обмена данными по анонимному каналу сервер и клиенты
канала должны синхронизировать доступ к этому каналу. То есть для организации передачи данных необходимо разработать протокол передачи данных или использовать объекты синхронизации, которые исключают одновременный неконтролируемый доступ параллельных потоков к анонимному каналу. .
№ 2. Создайте программы, в которых стандартный ввод-вывод перенаправляется в анонимный канал, а для обмена данными по анонимному каналу используются перегруженные операторы ввода-вывода С++. Должны быть следующие программы: программа процесса-сервера анонимного канала. Эта программа создает двух клиентов анонимного канала и прекращает работу. Программы двух клиентов представляют собой: 1. Программу
процесс-клиента, записывающего данные в анонимный канал;
2. Программу процесс-клиента, читающего данные из анонимного канала. Программа
процесс-сервера создает клиентов и передает им дескрипторы анонимного канала через
поля структуры STARTUPINFO.
Контрольные вопросы
1. Как реализовать простейший канал передачи данных между процессами?
2. Какими характеристиками обладает анонимный канал связи?
3. Какие функции используются для создания анонимного канала и обмена данными
по нему?
4. Какой тип взаимодействия обеспечивают анонимные каналы?
5. Какие существуют ограничения при использовании анонимных каналов?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
6
4
Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.: ООО
«Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 6 (4 часа)
Тема: Работа с виртуальной памятью
Цель: Изучить использование виртуальной памяти
Краткие теоретические сведения
Под логической памятью процесса понимается массив байтов, к которым может обратиться процесс. Индекс каждого элемента массива называется логическим адресом. Так как
логическая память процесса представляется линейным массивом байтов, то логический
адрес процесса обычно называют линейным адресом. Линейный адрес процесса в Windows, обычно, состоит из 32 бит и изменяется в пределах от 0х00000000 до 0хFFFFFFFF .
Это теоретически позволяет процессу обращаться к 4 Гбайт логической памяти. Во время
работы процесса необходимо отображать логическую память процесса в физическую память компьютера. Обычно прямое отображение невозможно, так как объем логической
памяти процесса превышает объем физической памяти. Для решения этой задачи физическую память компьютера дополняют памятью на дисках. Полученную расширенную память называют виртуальной памятью, а адрес элемента этой памяти называют виртуальным адресом. Преобразование линейного адреса процесса в виртуальный адрес выполняется операционной системой посредством настройки регистров процессора. Преобразование виртуального адреса в физический адрес выполняется аппаратно (процессором).
Для реализации преобразования виртуального адреса в физический, виртуальную память
делят на блоки одинаковой длины, обычно равной 4Кбайт, которые называют страницами.
При обращении процесса по адресу в виртуальной странице, если необходимо, то происходит загрузка этой страницы в реальную память компьютера и настройка адресного пространства процесса на работу с этой страницей. Учитывая страничную организацию виртуальной памяти, фактически адрес делится на две части: старшую и младшую. Старшая
часть адреса рассматривается как номер страницы в реальной или виртуальной памяти,
младшая часть – как смещение внутри этой страницы. Для преобразования виртуальных
адресов в реальные адреса в системной области физической памяти для каждого процесса
хранится таблица страниц. Адрес таблицы страниц хранится в
специальной таблице, называемой каталогом таблиц страниц.
Страницы виртуальной памяти процесса могут находиться в одном из трех состояний:
 свободны для использования (free);
 распределены процессу для использования (committed);
 зарезервированы, но не используются процессом (reserved);
Задание.
№ 1. Спроектируйте и проведите эксперименты для оценки выигрыша в производительности, достигаемого за счет использования флага HEAP_NO_SERIALIZE при вызове
функций HeapCreate и HeapAlloc. Как зависит этот показатель от размера кучи и размера
блока?
№ 2 . Измените тестовую программу из предыдущего задания таким образом, чтобы она
позволяла определить, генерирует ли функция malloc исключения или она возвращает
6
5
нулевой указатель в случае нехватки памяти. Является ли обнаруженное поведение функции корректным?
№ 3. Создайте приложение, реализующее ограниченную версию UNIX-команды sort за
счет создания бинарного дерева поиска с использованием двух куч. Ключи размещаются в
куче узлов (node heap), представляющей дерево поиска.Каждый узел содержит левый и
правый указатели, ключ и указатель на запись в куче данных (data heap). Куча узлов состоит из блоков фиксированного размера, тогда когда куча данных содержит строки переменной длины. Отсортированный файл выводится путем обхода дерева.
Контрольные вопросы
1 Какие методы управления памятью реализованы в Windows?
2 Что представляет собой динамически созданная куча?
3 Какие преимущества дает использование независимых куч?
4 В каких функциях используется флаг HEAP_NO_SERIALIZE и почему использование
этого флага может обеспечивать незначительный выигрыш в производительности?
5 Для чего используется функция уплотнения кучи?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.: ООО
«Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 7 (2 часа)
Тема: Динамически подключаемые библиотеки
6
6
Цель: Изучить использование создания библиотек DLL и их подключение к программе
Краткие теоретические сведения
Модуль DLL можно загружать статически и динамически. Для использования в приложении статически связанного модуля DLL –это включить в файлы .cpp приложения директивы включения файла заголовка DLL, а в состав проекта включить соответствующий .libфайл.
Для динамического связывания модуля DLL с основным приложением нужно выполнить
следующие операции:
1 Загрузить DLL и получить указатель на этот модуль.
2 Извлечь указатель на функцию, размещенную в DLL, которую требуется вызвать.
3 Вызвать функцию.
4 Освободить память, занятую модулем DLL
Задание
Выполнить создание и использование библиотек позволяющих получить сумму двух чисел с плавающей запятой и получить факториал целого числа, библиотеки подгружать
статически и динамически. Порядок выполнения рассмотрен в разделе «Ход выполнения
работы».
Контрольная работа. Используя последовательность создания статических и динамических библиотек в разделе «Ход выполнения работы», создать библиотеки для выполнения
следующих задач:
1. в приложении в текстовом поле вводится алгебраическое выражение многочлена
(например, 5x4+3x3+2x2+7y+5;
вводятся значения диапазона изменения переменных;
2. затем выражение анализируется на неприрывность;
3. значения записываются в файл;
4. затем по ним строится график (количество точек предлагается выбрать);
5. полученный график можно масштабировать;
6. полученный график можно рассматривать на сетке;
7. полученный график можно вращать вокруг осей X,Y или заданной прямой, при этом
должно получится изображение трехмерной (3D) графики (что, похожее на модификатор Lathe) постараться создать удобный интерфейс, что похожее , но для 3 х мерной графики:
6
7
Контрольные вопросы
.1Чем отличаются статическое связывание библиотеки от динамической загрузки?
.2 Как библиотеки помещаются в адресное пространство процесса?
.3Как управлять версиями DLL?
.4Как реализован механизм отображения файлов?
.5Для чего используется файл определения модуля (def) ?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.: ООО
«Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
6
8
Практическое занятие № 8-1 (2часа)
Тема: Асинхронная обработка данных
Цель: Изучить асинхронный вызов процедур
Краткие теоретические сведения
Асинхронной процедурой называется функция, которая исполняется асинхронно в
контексте какого-либо потока. Для исполнения асинхронной процедуры необходимо
выполнить три условия:

определить асинхронную процедуру;

определить поток, в контексте которого эта процедура будет выполняться;

дать разрешение на выполнение асинхронной процедуры.
Асинхронная процедура должна определяться функцией, которая имеет следующий прототтип:
VOID CALLBACK имя_асинхронной_процедуры(DWORD dwParam)
Для определения потока, в контексте которого исполняется асинхнонная процедура, используется функция QueueUserAPC, которая связывает асинхронную процедуру с потоком.
Задание
№ 1. Создайте приложение, в котором функция WaitForSingleObjectsEx используется
для ожидания события или включения асинхронной процедуры в очередь потока.
№ 2. Создайте приложение, в котором функция SignalObjectAndWait используется для
оповещения о наступлении события и одновременном ожидании наступления другого
события или включения асинхронной процедуры в очередь потока.
Контрольные вопросы
1. Какой прототип имеет функция асинхронной процедуры? Объясните назначение параметров этой функции.
2. В какой момент времени выполняется асинхронная процедура?
3. Как установит асинхронную процедуру в очередь потока?
4. Объясните назначение параметров функции QueueUserAPC.
5. Какие функции используются для ожидания наступления некоторого события
или выполнения асинхронной процедуры?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
6
9
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Практическое занятие № 8-2 (2 часа)
Тема: Асинхронная обработка данных
Цель: Изучить использование функций асинхронной записи данных и асинхронного чтения данных
Краткие теоретические сведения
При асинхронной записи данных в файл или чтении данных из файла , после выдачи
команды на запись или чтение данных, поток не блокируется, а продолжает свою работу.
Для асинхронноговвода-вывода данных в ОС Windows используются те же
функции ReadFile и WriteFile, что и для синхронного ввода-вывода. Но в этом случае
файл должен быть открыт в режиме FILE_FLAG_OVERLAPPED. Поток узнает о завершении асинхронной операции ввода-вывода двумя способами.
Первый способ заключается в том, что для этого можно использовать дескриптор
файла, который устанавливается в несигнальное состояние после начала каждой асинхронной операции записи или чтения. Второй способ заключается в использовании
специального события, которое устанавливается ОС в сигнальное состояние при завершении асинхронной операции ввода-вывода.
Задание.
№1. Создайте приложение, в котором выполняется асинхронная запись данных в файл.
В программе для сигнализации о завершении операции вывода используется дескриптор файла.
№2. Создайте приложение, в котором выполняется асинхронная запись данных в файл.
В программе для сигнализации о завершении операции вывода используется событие.
7
0
№ 3. Создайте приложение, в котором выполняется асинхроннаое чтение данных из
файла. В программе для сигнализации о завершении операции ввода используется дескриптор файла
№ 4. Создайте приложение, в котором выполняется асинхроннаое чтение данных из
файла. В программе для сигнализации о завершении операции ввода используется
событие.
№ 5. Создайте приложение, в котором сначала асинхронно блокируется доступ к
файлу , а затем выполняется разблокирование доступа к файлу.
№ 6. Создайте приложение, в котором функция GetOverlappedResult используется для
определения состояния асинхронной операции записи данных в файл.
№ 7. Создайте приложение, в которой для записи данных в файл используется функция WriteFileEx..
№ 8. Создайте приложение, в которой для чтения данных из файла используется
функция ReadFileEx.
Конторольные вопросы
1.Какие поля определены в структуре OVERLAPPED?
2. Чем отличается асинхронное чтение данных с использованием дескриптора файла от
асинхронного чтения с использованием события?
3.Как выполняется асинхронное блокирование файла для монополного доступа?
4.Как определить состояние асинхронной операции ввода-вывода?
5. Как определить процедуру завершения ввода-вывода?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
7
1
5. Тематика и планы лабораторных работ по изученному материалу
Лабораторная работа № 1 (2 часа)
Тема: Управление файлами
Цель: Изучить функции Win32 API для работы с файлами
Задание
№ 1. Создайте приложение, в котором производится копирование файлов с
преобразованием из ASCII в Unicode с использованием функций Win32 API . Определите
как изменилась производительность программы, если задать флаг
FILE_FLAG_SEQUENTIAL_SCAN при вызове функции CreateFile.
№ 2. Напишите программу mv, которая реализует одноименную команду UNIX,
позволяющую переместить целиком любой каталог. При этом имеет существенное
значение, осуществляется ли перемещение файла или каталога на другой диск или они
остаются на прежнем месте. В случае смены диска используйте операцию копирования
файлов, в противном случае используйте команды MoveFile или MoveFileEx.
№ 3. Напишите программу, которая блокирует заданный файл и удерживает его в
блокированном состоянии в течение длительного времени. Воспользовавшись любым
текстовым редактором, попытайтесь получить доступ к файлу (используйте текстовый
файл) в период действия блокировки. Что при этом происходит? Заблокирован ли файл
должным образом? Также напишите программу, предлагающую пользователю задать
блокировку для текстового файла. Чтобы проверить, срабатывает ли блокировка должным
образом, запустите на выполнение два экземпляра программы в разных окнах.
Контрольные вопросы
1 Какими функциями выполнять блокирование файла?
2 Как частично заблокировать файл? Приведите пример.
3 Наследуются ли блокировки? Кто является хозяином блокировки?
4 Какие типы блокировок можно установить для блокировки файла?
5 Какие функции определены для управления реестром?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
7
2
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная работа № 2-1 (2 часа)
Тема: Управление потоками и процессами
Цель: Изучить использование функции Win32 API для работы с потоками и процессами
Задание
№ 1.Создайте многопоточное приложение, в котором основной поток поручает выполнение отдельных задач рабочим потокам:
 Каждый рабочий поток получает файл, в котором он должен выполнить поиск в
текстовом файле на соответствие введенному образцу , а полученные рабочим потоком результаты передаются главному потоку во временном файле; затем выводится количество совпадений результатов поиска.
 Создается рабочая группа, в которой рабочие потоки объединяют свои усилия по
выполнению сортировки слиянием. В первом случае данные из внешнего файла
считываются основным потоком, во втором случае каждый поток самостоятельно
считывает необходимую часть файла.
7
3
№ 2. Реализуйте приложение WIN API c набором функций, позволяющих приостанавливать и возобновлять выполнение потоков, и кроме того, получать значение счетчика приостановок потоков. (используется )
№ 3. Создайте приложение, позволяющее выполнять поиск в каждом из файлов, указанных в командной строке, для этого создается отдельный процесс. Каждому процессу
предоставляется временный файл в текущем каталоге, в котором сохраняются результаты
поиска. Затем все результаты помещаются в один файл, причем все результаты должны
быть записаны в заданном, определенном порядке.
Контрольные вопросы
1 Как правильно выполнять разблокирование файла?
2 Какая функция используется для получения информации о файле?
3 Какие поля определены в структуре BY_HANDLE_FILE_INFORMATION?
4 Какие поля определены в структуре FILETIME?
5 Какая функция используется для преобразования времени в системный формат?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная работа № 2-2
Тема: Обслуживание потоков
Цель: Изучить назначение и изменение приоритетов процессов и потоков
Краткие теоретические сведения
Операционные системы Windows распределяют процессорное время между потоками в
соответствии с их приоритетами. По истечении кванта времени исполнение текущего потока прерывается, его контекст запоминается и процессорное время передается потоку с
высшим приоритетом. Приоритеты потоков в Windows определяются относительно приоритета процесса, в контексте которого они выполняются и изменяются от 0 до 31. Приоритет процессов устанавливается при их создании функцией CreateProcess, используя
параметр dwCreationFlags. Для установки приоритета процесса в этом параметре нужно
установить один из следующих флагов:
7
4
 IDLE_PROIRITY_CLASS –класс фоновых процессов;
 BELOW_NORMAL_PRIORITY_CLASS –класс процессов ниже нормальных;
 NORMAL_PRIORITY_CLASS – класс нормальных процессов:
 ABOVE_NORMAL_PRIORITY_CLASS- класс процессов выше нормальных;
 HIGH_PRIORITY_CLASS – класс высокоприоритетных процессов;
 REAL_TIME_PRIORITY_CLASS – класс процессов реального времени.
Предполагается, что операционная система Windows различает четыре типа процессов в
соответствии с их приоритетами:
 Фоновые процессы выполняют свою работу, когда нет активных пользовательских
процессов. Обычно эти процессы следят за состоянием системы. Приоритет таких
процессов устанавливается флагом IDLE_PROIRITY_CLASS.
 Процессы с нормальным приоритетом – это обычные пользовательские процессы. Приоритет таких процессов устанавливается флагом
NORMAL_PRIORITY_CLASS. Этот приоритет также назначается пользовательским процессам по умолчанию. В Windows 2000 приоритет обычных пользовательских может также устанавливаться флагами BELOW_NORMAL_PRIORITY_CLASS и ABOVE_NORMAL_PRIORITY_CLASS,
которые соответственно немного повышают или понижают приоритет пользовательского процесса.
 Процессы с высоким приоритетом –это такие пользовательские процессы, от которых требуется более быстрая реакция на некоторые события, чем от обычных
пользовательских процессов. Приоритет таких процессов устанавливается флагом HIGH_PRIORITY_CLASS. Эти процессы должны содержать небольшой программный код и выполняться очень быстро, чтобы не замедлять работу системы.
 Процессы реального времени- это такие процессы, приоритет которых устанавливается флагом REAL_TIME_PRIORITY_CLASS. Работа таких процессов обычно
происходит в масштабе реального времени и связана с реакцией на внешние события. Эти процессы должны работать непосредственно с аппаратурой.
Приоритет процесса можно изменить при помощи функции
BOOL SetPriorityClass (HANDLE hProcess, DWORD dwPriorityClass);
При успешном завершении функция возвращает ненулевое значение, в противном случае
– FALSE. Параметр dwPriorityClass должен быть равен одному из флагов приоритета.
Узнать приоритет процесса можно посредством вызова функции GetPriorityClass:
DWORD GetPriorityClass(HANDLE hProcess);
Приоритет потока, который учитывается системой при выделении потокам процессорного
времени, называется базовым или основным приоритетом потока. Всего существует 32
базовых приоритете – от 0 до 31. Для каждого базового приоритета существует очередь
потоков. При диспетчеризации потоков квант процессорного времени выделяется потоку,
который стоит первым в очереди с наивысшим базовым приоритетом. Базовый приоритет
потока определяется как сумма приоритета процесса и уровня приоритета потока, который может принимать одно из следующих значений:
первая группа
 THTEAD_PRIORITY_LOWEST- низший приоритет;
 THTEAD_PRIORITY_BELLOW_NORMAL- приоритет ниже нормального;
 THTEAD_PRIORITY_NORMAL –нормальный приоритет;
 THTEAD_PRIORITY_ABOVE_NORMAL – приоритет выше нормального;
 THTEAD_PRIORITY_HIGHEST- высший приоритет;
вторая группа
 THTEAD_PRIORITY_IDLE – приоритет фонового потока;
 THTEAD_PRIORITY_TIME_CRITICAL – приоритет потока реального времени.
7
5
Значения приоритета потока из первой группы в сумме с приоритетом процесса, в контексте которого этот поток выполняется, уменьшают, оставляют неизменными или увеличивают значение базового приоритета потока соответственно на величину -2, -1, 0, 1, 2.
Уровень приоритета потока THTEAD_PRIORITY_IDLE устанавливает базовый приоритет
потока равным 16, если приоритет процесса, в контексте которого выполняется поток, равен REAL_TIME_PRIORITY_CLASS, и 1 –в остальных случаях. Уровень приоритета
потока THTEAD_PRIORITY_TIME_CRITICAL устанавливает базовый приоритет потока
равным 31, если приоритет процесса, в контексте которого выполняется поток, равен
REAL_TIME_PRIORITY_CLASS, и 15 в остальных случаях.
Real
High
Above
Normal Below Idle
time
normal
normal
Time critical
31
15
15
15
15
15
Highest
26
15
12
10
8
6
Above normal
25
14
11
9
7
5
Normal
24
13
10
8
6
4
Below normal
23
12
9
7
5
3
Lowest
22
11
8
6
4
2
Idle
16
1
1
1
1
1
Таблица1. Базовые приоритеты потоков
При создании потока его базовый приоритет устанавливается как сумма приоритета процесса, в контексте которого этот поток выполняется, и уровня приоритета потока
THTEAD_PRIORITY_NORMAL. Для изменения приоритета потока используется функция
SetThreadPriority:
BOOL SetThreadPriority(HANDLE hThread,
// дескриптор потока
Int nPriority
//уровень приоритета потока
);
При удачном завершении функция SetThreadPriority возвращает ненулевое значение, в
противном случае FALSE.
Узнать уровень приоритета потока можно посредством вызова функции GetThreadPriority,
которая имеет следующий прототип:
DWORD GetThreadPriority(HANDLE hThread);
При успешном завершении эта функция возвращает одно из значений уровня приоритета,
в противном случае она возвращает значение THREAD_PRIORITY_ERROR_RETURN.
Базовый приоритет потока может динамически изменяться, если этот приоритет находится в пределах между уровнями от 0 до 15. При получении потоком сообщения или при его
переходе в состояние готовности система повышает базовый приоритет этого потока на 2.
В процессе выполнения базовый приоритет такого потока понижается на 1 с каждым отработанным квантом времени, но никогда не опускается ниже базового приоритета.
В операционной системе Windows 2000 возможно программное управление режимом динамического изменения базовых приоритетов потоков. Отмена или возобновление режима
динамического изменения базового приоритета всех потоков, исполняемых в контексте
процесса, выполняется при помощи функции SetProcessPriorityBoost, которая имеет следующий прототип:
BOOL SetProcessPriorityBoost(
HANDLE hProcess,
//дескриптор процесса
BOOL pDisablePriorityBoost
//состояние повышения приоритета
);
При удачном завершении функция SetProcessPriorityBoost возвращает ненулевое значение, в противном случае FALSE. Значение булевой переменной, на которую указывает параметр pDisablePriorityBoost, определяет состояние режима динамического повышения
базовых приоритетов потоков. Если это значение равно TRUE, то режим динамического
7
6
повышения базовых приоритетов потоков, выполняемых в контексте процесса с дескриптором hProcess, запрещен. И наоборот, если значение этого параметра равно FALSE , то
режим динамического повышения базовых приоритетов этих потоков разрешен.
Узнать, разрешен ли режим динамического повышения базовых приоритетов, можно посредством функции GetProcessPriorityBoost, которая имеет следующий прототип:
GetProcessPriorityBoost ( HANDLE hProcess,
//дескриптор процесса
PBOOL DisablePriorityBoost //состояние повышения приоритета
);
Для отмены или возобновления режима динамического изменения базового приоритета
только одного потока используется функция
SetThreadPriorityBoost ( HANDLE hThread,
//дескриптор потока
BOOL DisablePriorityBoost
//состояние повышения приоритета
);
Чтобы определить, разрешен ли режим динамического повышения базового приоритета
для какого-то конкретного потока, используется функция GetThreadPriorityBoost, которая
имеет следующий прототип:
GetThreadPriorityBoost ( HANDLE hThread,
//дескриптор потока
PBOOL DisablePriorityBoost //состояние повышения приоритета
);
Эта функция работает так же, как и функция GetProcessProrityBoost, но только для одного
потока с дескриптором hThread.
Задание
№ 1. Создайте приложение, в котором запрашивается приоритет текущего процесса. Выведите значение, возвращаемое функцией GetPriorityClass(),отобразите это значение на
экране. Затем поочередно установите фоновый приоритет текущего процесса, получите
значение, возвращаемое функцией GetPriorityClass() и отобразите это значение на экране
и высокий приоритет. Примечание. Числовые значения флагов не соответствуют числовым значениям приоритетам процессов.
№ 2. Создайте приложение, в котором сначала получите псевдодескриптор текущего потока (GetCurrentThread() ), затем узнайте уровень приоритета текущего процесса и отобразите на экране доступным способом, затем понизьте приоритет текущего потока,
например, SetThreadPriority(hThread, THREAD_PRORITY_LOWEST), узнайте уровень
приоритета и отобразите на экране, затем повысьте уровень приоритета и результат отобразите на экране.
№ 3.Создайте приложение, в котором устанавливается, а затем отменяется режим динамического изменения базовых приоритетов всех потоков и только одного потока.
Контрольные вопросы
1. Что понимается под термином “вытесняющая многозадачность” ?
2. Каким образом в Windows определена система приоритетов выполнения тех или
иных процессов и потоков?
3. Зачем операционной системе может потребоваться динамическое изменение приоритетов потоков?
4. Какой приоритет имеет утилита “Диспетчер задач”?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
7
7
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная работа № 3
Тема: Синхронизация потоков и процессов
Цель: Изучить назначение объектов синхронизации
Краткие теоретические сведения
Мьютексы
Для решения проблемы взаимного исключения между параллельными потоками, выполняющимися в контекстах разных процессов, в операционных системах Windows используется объект ядра мьютекс. Мьютекс находится в сигнальном состоянии, если он не
принадлежит ни одному потоку. В противном случае мьютекс находится в несигнальном
состоянии. Одновременно мьютекс может принадлежать только одному потоку.
Потоки, ждущие сигнального состояния мьютекса, обслуживаются в порядке FIFO. Однако если поток ждет наступления асинхронного события, то функции ядра могут исключить поток из очереди к мьютексу для обслуживания наступления этого события. После
этого поток становится в конец очереди мьютекса.
Создается мьютекс вызовом функции CreateMutex, которая имеет следующий прототип:
HANDLE CreateMutex (
LPSECURITY_ATTRIBUTES lpMutexAttributes, // атрибуты защиты
BOOL bInitialOwner,
// начальный владелец мьютекса
LPCTSTR lpName
// имя мьютекса
);
Если значение параметра lpMutexAttributes установить в NULL, это означает, что атрибуты защиты заданы по умолчанию, т.е. дескриптор мьютекса не является наследуемым и
доступ к мьютексу открыт для всех пользователей.
Задание
№1. Создайте приложение, в котором реализуется создание защищенных структур данных для хранения состояний объектов (используются объекты CRITICAL_SECTION).
В приложении выполняются следующие задачи:
 Имеются два потока, работающие в полностью асинхронном режиме;
 Первый поток периодически создает сообщения, содержащие таблицу чисел,
например, курсы валют, эта таблица периодически обновляется;
 По требованию пользователя второй поток отображает текущие данные. Требуется, чтобы отображаемые данные представляли собой самый последний полный
набор данных, но никакие данные не должны отображаться дважды;
7
8

Данные не должны отображаться в те промежутки времени, когда они обновляются первым потоком, устаревшие данные также не должны отображаться. Некоторые сообщения никогда не используются.
 В качестве средства контроля целостности данных первый поток вычисляет простую контрольную сумму данных таблицы, которая сравнивается с аналогичной
суммой, вычисленной вторым потоком. Данные, полученные при обращении к таблице в моменты ее обновления, будут недействительными; использование объектов CRITICAL_SECTION гарантирует, что этого никогда не произойдет;
 Оба потока поддерживают статистику суммарного количества отправленных, полученных и утерянных сообщений.
№ 2. Создайте приложение, в котором реализуется использование объектов mutex. В приложении решаются следующие задачи:
 Имеется два связных списка, список А и список В, каждый из которых содержит
идентичные структуры и поддерживается рабочими потоками.
 Для одного класса элементов списка корректность операции зависит от того факта,
что данный элемент X находится или отсутствует одновременно в обоих списках;
 В других ситуациях допускается нахождение элемента только в одном из списков,
но не в обоих одновременно. Например, указанными списками могут быть списки
сотрудников отделов А и В, когда некоторым сотрудникам разрешена работа одновременно в двух отделах;
 В этой связи, для обоих списков требуются различные мьютексы, но при добавлении или удалении общих элементов списков блокироваться должны оба мьютекса .
 Устраните взаимоблокировку мьютексов, используя функцию
WaitForSingleObject(), или предварительно определите “иерархию мьютексов”.
№ 3. Создайте приложение, в котором реализуется использование объектов semaphores.В
приложении решаются следующие задачи:
 Объект семафор используется для ограничения количества рабочих потоков, фактически выполняющихся в любой момент времени (3или 4);
Контрольные вопросы
 Как влияет синхронизация на производительность программ?
 Как установить значение спин – счетчика?
 В каких целях используются спин - счетчики ?
 Какими достоинствами и недостатками обладают объекты CRITICAL SECTION?
 Как выполняется настройка производительности SMP-систем с помощью спинсчетчиков?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
7
9
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная работа № 4 (4 часа)
Тема: Обмен данными между параллельными процессами
Цель: Изучить функции для работы с именованными каналами в Windows
Краткие теоретические сведения
Именованным каналом называется объект ядра ОС, который обеспечивает передачу данных между процессами, выполняющимися на компьютерах в одной локальной сети. Процесс, который создает именованный канал, называется сервером именованного канала.
Процессы, которые связываются с именованными каналом, называются клиентами именованного канала. Основные характеристики именованных каналов:
имеют имя, которое используется клиентами для связи с именованным каналом;
могут быть как полудуплексные, так и дуплексные;
передача данных может осуществляться как потоком, так и сообщениями;
обмен данными может быть как синхронным, так и асинхронным;
возможность моделирования любой топологии связей.
Порядок работы с именованными каналами:
создание именованного канала сервером;
соединение сервера с экземпляром именованного канала;
соединение клиента с экземпляром именованного канала;
обмен данными по именованному каналу;
отсоединение сервера от экземпляра именованного канала;
закрытие именованного канала клиентом и сервером.
Создание именованных каналов
Именованные каналы создаются процессом-сервером при помощи функции :
HANDLE CreateNamedPipe (
LPCTSTR lpName,
//имя канала
DWORD dwOpenMode,
//атрибуты канала
DWORD dwPipeMode,
//режим передачи данных
DWORD nMaxInstances, //максимальное количество экземпляров канала
DWORD nOutBufferSize,
//размер выходного буфера
DWORD nInBufferSize,
//размер входного буфера
DWORD nDefaultTimeOut, //время ожидания связи с клиентом
LPSECURITY_ATTRIBUTES lpPipeAttributes );//атрибуты безопасности
При удачном завершении функция CreateNamedPipe возвращает дескриптор именованного канала, в случае неудачи -одно из двух значений:
INVALID_HANDLE_VALUE — неудачное завершение ;
ERROR_INVALID_PARAMETR — значение параметра nMaxInstances больше, чем
величина PIPE_INVALID_INSTANCES
Параметры этой функции:
Параметр lpName указывает на строку, которая должна иметь вид : \\.\pipe\pipe_name
Здесь «.» обозначает локальную машину, так как новый именованный канал всегда
создается на локальной машине, слово «pipe» фиксировано, «pipe_name»
обозначает имя канала, задается пользователем, нечувствительно к регистру.
Параметр dwOpenMode задает флаги форматирования, которые определяют
8
0
направление передачи данных, буферизацию, синхронизацию обмена данными и права
доступа к именованному каналу. Для определения направления передачи данных
используются флаги:
PIPE_ACCESS_DUPLEX - чтение и запись в канал;
PIPE_ACCESS_INBOUND — клиент пишет, а сервер читает данные;
PIPE_ACCESS_OUTBOUND — сервер пишет, а клиент читает данные
Кроме того, каждый из этих флагов позволяет использовать дескриптор канала для синхронизации.
Флаг, определяющий направление передачи данных по именованному каналу должен совпадать для всех экземпляров одного и того именованного канала. Для определения способа буферизации и синхронизации используются флаги:
FILE_FLAG_WRITE_THROUGH – запрещает буферизацию при передаче данных по
сети
FILE_FLAG_OVERLAPPED – разрешает асинхронную передачу данных по каналу
Эти флаги могут быть разными для каждого экземпляра одного и того же именованного
канала.
Флаги PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, PIPE_ACCESS_OUTBOUND
определяют специфические права доступа к именованному каналу, которые включают
следующие родовые права доступа:
7 PIPE_ACCESS_DUPLEX - включает родовые права доступа GENERIC_READ,
GENERIC_WRITE и SYNCHRONIZE;
8 PIPE_ACCESS_INBOUND – включает родовые права доступа GENERIC_READ и
SYNCHRONIZE;
9 PIPE_ACCESS_OUTBOUND – включает родовые права доступа GENERIC_WRITE
и SYNCHRONIZE;
Параметр dwPipeMode задает флаги, определяющие способ передачи данных по именованному каналу. Для определения способов чтения и записи данных в именованный канал
используются флаги:
2.PIPE_TYPE_BYTE – запись данных потоком;
3.PIPE_TYPE_MESSAGE – запись данных сообщениями;
4.PIPE_READMODE_BYTE – чтение данных потоком;
5.PIPE_READMODE_MESSAGE – чтение данных сообщениями.
По умолчанию данные по именованному каналу передаются потоком. Флаги, определяющие способ чтения и записи данных в именованный канал, должны совпадать для всех экземпляров одного и того же канала. Для определения синхронизации доступа к именованному каналу используются флаги:
3.PIPE_WAIT –синхронная связь с каналом и обмен данными по каналу;
4.PIPE_NOWAIT – асинхронная связь с каналом и обмен данными по каналу.
Эти флаги могут быть разными для каждого экземпляра именованного канала.
Параметр nMaxInstance определяет максимальное число экземпляров именованного канала, которое может находиться в пределах от 1 до PIPE_UNLIMITED_INSTANCES. Каждый экземпляр канала предназначен для обмена данными по каналу между сервером и отдельным клиентом.
Параметры nOutBufferSize и nInBufferSize определяют соответственно размеры выходного и входного буферов для обмена данными по именованному каналу. Размеры буферов
определяет ОС.
Параметр nDefaultTimeOut устанавливает время ожидания клиентом связи с сервером.
Это время используется при вызове клиентом функции WaitNamedPipe. В этой функции
параметр nTimeOut имеет значение NMPWAIT_USE_DEFAULT_WAIT.
Для связи сервера с несколькими клиентами по одному именованному каналу сервер должен создать несколько экземпляров этого канала. Каждый экземпляр именованного канала создается вызовом функции CreateNamedPipe, которая возвращает дескриптор экзем8
1
пляра именованного канала. Поток, создающий экземпляр именованного канала, должен
иметь право доступа FILE_CREATE_PIPE_INSTANCE к именованному каналу.Этим правом по умолчанию обладает владелец.
Соединение сервера с клиентом
После того как сервер создал именованный канал, он должен дождаться соединения клиента с этим каналом. Для этого сервер вызывает функцию ConnectNamedPipe:
BOOL ConnectNamedPipe (
HANDLE hNamedPipe,
//дескриптор канала
LPOVERLAPPED lpOverlapped ); //асинхронная связь
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи - значение FALSE. Сервер использует эту функцию для связи с клиентом по
каждому свободному экземпляру именованного канала. После окончания обмена данными
с клиентом сервер может вызвать функцию DisconnectNamedPipe, которая имеет следующий прототип:
BOOL DisconnectNamePipe (
HANDLE hNamedPipe
//дескриптор канала
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи - значение FALSE. Эта функция разрывает связь сервера с клиентом. После разрыва связи с одним клиентом сервер снова может вызвать ConnectNamedPipe, чтобы установить связь по этому же именованному каналу с другим клиентом.
Соединение клиентов с именованным каналом
Прежде чем соединяться с именованным каналом, клиент должен определить, доступен
ли какой-либо экземпляр этого канала для соединения. Клиент должен вызвать функцию
WaitNamedPipe, которая имеет следующий прототип:
BOOL WaitNamedPipe (
LPCTSTR lpNamedPipeName,
//указатель на имя канала
DWORD nTimeOut
//интервал ожидания
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи - значение FALSE. Параметры этой функции:
Параметр lpNamedPipeName указывает на строку, которая должна иметь вид:
\\server_name\pipe\\pipe_name
где server_name обозначает имя компьютера, на котором выполняется сервер именованного канала, слово pipe фиксировано, pipe_name задает имя именованного канала.
Параметр nTimeOut задает временной интервал, в течение которого клиент ждет связь с
сервером. Этот временной интервал определяется в миллисекундах или может быть равен
одному из следующих значений:
6. NMPWAIT_USE_DEFAULT_WAIT - интервал времени ожидания определяется
значением параметра nDefaulttimeOut, который задается в функции
CreateNamedPipe
7. NMPWAIT_WAIT_FOREVER – бесконечное время ожидания связи с
именованным каналом.
Замечание. Если не существует экземпляров именованного канала с именем
lpNamedPipe, то функция WaitNamedPipe немедленно завершается неудачей независимо
от времени ожидания. Если клиент соединяется с каналом до вызова сервером функции
ConnectNamedPipe, то функция WaitNamedPipe возвращает значение FALSE.
После того как обнаружен свободный экземпляр канала, чтобы установить связь с этим
каналом клиент должен вызвать функцию CreateFile, которая имеет следующий прототип:
HANDLE CreateFile (
LPCTSTR lpFileName,
//указатель на имя канала
8
2
DWORD dwDesiredAccess,
//чтение или запись в канал
DWORD dwShareMode,
//режим совместного использования
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
//атрибуты безопасности
DWORD dwCreationDisposition, //флаг открытия канала
DWORD dwFlagsAndAttributes, //флаги и атрибуты
HANDLE hTemplateFile
//дополнительные атрибуты
);
В случае успешного завершения эта функция возвращает дескриптор именованного канала, а в случае неудачи – значение INVALID_HANDLE_VALUE.
Если функция используется для открытия именованного канала, то ее параметры могут
принимать следующие значения:
Параметр lpFileName должен указывать на имя канала, которое должно быть задано в том
же формате, что и в функции WaitNamedPipe. Если клиент работает на той же машине,
что и сервер, и использует для открытия именованного канала в функции CreateFile имя
канала как \\.\pipe\pipe_name, то файловая система именованных каналов (Named Pipe File
System, NPFS) открывает этот именованный канал в режиме передачи данных потоком.
Чтобы открыть именованный канал в режиме передачи данных сообщениями нужно задать имя канала в виде:
\\server_name|pipe\pipe_name
Параметр dwDesiredAccess может принимать одно из следующих значений:
6. 0 – разрешает получить атрибуты канала;
7. GENERIC_READ – разрешает чтение из канала;
8. GENERIC_WRITE – разрешает запись в канал
Функция CreateFile завершается неудачей, если доступ к именованному каналу, заданный
этими значениями, не соответствует значениям параметра dwOpenMode в функции CreateNamedPipe.
Параметр dwShareMode определяет режим совместного использования именованного канала и может принимать значение 0, которое запрещает совместное использование именованного канала или любую комбинацию следующих значений:
6. FILE_SHARE_READ – разрешает совместное чтение из канала;
7. FILE_SHARE_WRITE – разрешает совместную запись в канал.
Параметр lpSecurityAttributes задает атрибуты безопасности именованного канала (по
умолчанию NULL).
Для именованного канала параметр dwCreationDisposition должен быть равен значению
OPEN_EXISTING, так как клиент всегда открывает существующий именованный канал.
Для именованного канала параметр dwFlagsAndAttributes можно задать равным 0, что
определяет флаги и атрибуты по умолчанию.
Значение параметра hTemplateFile задается равным NULL.
Замечание. Несмотря на то, что функция WaitNamedPipe завершилась успешно, последующий вызов функции CreateFile может завершиться неудачей по следующим причинам: между вызовами этих функций сервер закрыл канал или другой клиент связался с экземпляром этого канала.
Может возникнуть такая ситуация, что сервер вызвал функцию ConnectNamedPipe, а клиента, который хочет связаться с именованным каналом, не существует. В этом случае серверное приложение будет заблокировано. Чтобы иметь возможность обработать такую
ситуацию, функцию ConnectNamedPipe следует вызывать в отдельном потоке серверного
приложения. Тогда для разблокировки серверного приложения можно вызвать функцию
для связи клиента с именованным каналом из другого потока этого приложения.
Обмен данными по именованному каналу
Так как в случае именованного канала разрешен асинхронный обмен данными, то в функциях ReadFile и WriteFile может использоваться параметр lpOverlapped при том условии,
что в вызове функции CreateNamedPipe в параметре dwOpenMode был установлен флаг
8
3
FILE_FLAG_OVERLAPPED. Максимально в именованный канал может быть записано до
65535 байт одной операцией WriteFile. Кроме того, для асинхронного обмена данными
по именованному каналу могут использоваться также функции ReadFileEx, WriteFileEx.
После завершения обмена данными по именованному каналу потоки должны закрыть дескрипторы экземпляров именованного канала, используя функцию CloseHandle.
Пример обмена данными по именованному каналу:
Процесс-сервер создает именованный канал, а затем ждет, пока клиент не соединится с
именованным каналом. После этого сервер читает из именованного канала числа в цикле
и выводит их на консоль.
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hNamedPipe;
// создаем именованный канал для чтения
hNamedPipe = CreateNamedPipe(
"\\\\.\\pipe\\demo_pipe",
// имя канала
PIPE_ACCESS_INBOUND,
// читаем из канала
PIPE_TYPE_MESSAGE | PIPE_WAIT, // синхронная передача сообщений
1,
// максимальное количество экземпляров канала
0,
// размер выходного буфера по умолчанию
0,
// размер входного буфера по умолчанию
INFINITE, // клиент ждет связь бесконечно долго
NULL
// защита по умолчанию
);
// проверяем на успешное создание
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
cerr << "Create named pipe failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to exit.";
cin.get();
return 0;
}
// ждем, пока клиент свяжется с каналом
cout << "The server is waiting for connection with a client." << endl;
if(!ConnectNamedPipe(
hNamedPipe, // дескриптор канала
NULL // связь синхронная
))
{
cerr << "The connection failed." << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
8
4
// читаем данные из канала
for (int i = 0; i < 21; i++)
{
int nData;
DWORD dwBytesRead;
if (!ReadFile(
hNamedPipe, // дескриптор канала
&nData,
// адрес буфера для ввода данных
sizeof(nData), // число читаемых байтов
&dwBytesRead, // число прочитанных байтов
NULL
// передача данных синхронная
))
{
cerr << "Read file failed." << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// выводим прочитанные данные на консоль
cout << "The number " << nData << " was read by the server" << endl;
}
// закрываем дескриптор канала
CloseHandle(hNamedPipe);
// завершаем процесс
cout << "The data are read by the server."<<endl;
cout << "Press any key to exit.";
cin.get();
return 0;
}
Программа процесса-клиента именованного канала, который сначала связывается с именованным каналом, а затем записывает в него в цикле числа
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hNamedPipe;
char pipeName[] = "\\\\.\\pipe\\demo_pipe";
// связываемся с именованным каналом
hNamedPipe = CreateFile(
pipeName,
// имя канала
GENERIC_WRITE, // записываем в канал
FILE_SHARE_READ, // разрешаем одновременное чтение из канала
NULL,
// защита по умолчанию
OPEN_EXISTING, // открываем существующий канал
0, // атрибуты по умолчанию
8
5
NULL // дополнительных атрибутов нет
);
// проверяем связь с каналом
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
cerr << "Connection with the named pipe failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to exit.";
return 0;
}
// пишем в именованный канал
for (int i = 0; i < 21; i++)
{
DWORD dwBytesWritten;
if (!WriteFile(
hNamedPipe, // дескриптор канала
&i,
// данные
sizeof(i), // размер данных
&dwBytesWritten, // количество записанных байтов
NULL
// синхронная запись
))
{
// ошибка записи
cerr << "Writing to the named pipe failed: " << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// выводим число на консоль
cout << "The number " << i << " is written to the named pipe."
<< endl;
Sleep(1000);
}
// закрываем дескриптор канала
CloseHandle(hNamedPipe);
// завершаем процесс
cout << "The data are written by the client." << endl
<< "Press any key to exit.";
cin.get();
return 0;
}
Копирование данных из именованного канала
Для копирования данных из именованного канала используется функция PeekNamedPipe,
которая копирует данные в буфер, не удаляя их.
BOOL PeekNamedPipe (
8
6
HANDLE hNamedPipe,
//дескриптор канала
LPVOID lpBuffer,
//буфер данных
DWORD nBufferSize,
//размер буфера данных
LPDWORD lpBytesRead,
//количество прочитанных байтов
LPDWORD lpTotalBytesAvail,
//количество доступных байтов
LPDWORD lpBytesLeftThisMessage
//количество непрочитанных байтов
);
В случае успешного завершения функция возвращает ненулевое значение, в случае
неудачи FALSE. Если данных в канале нет, то функция немедленно возвращает управление и устанавливает в ноль значения переменных, на которые указывают параметры
lpBytesRead, lpTotalBytesAvail и lpBytesLeftThisMessage.
Параметры функции имеют следующее назначение:
 В параметре hNamedPipe должен быть установлен дескриптор именованного
канала, причем канал должен быть открыт в режиме чтения.
 Параметр lpBuffer должен указывать на область памяти, в которую функция читает
данные из именованного канала, если в этом параметре установлено значение
NULL, то данные из именованного канала читаться не будут.
 В параметре nBufferSize должен быть установлен размер области памяти, на
которую указывает параметр lpBuffer.
 Параметр lpBytesRead должен указывать на переменную типа DWORD, в которую
функция записывает количество прочитанных байтов. Если данные из
именованного канала не читаются, то значение этого параметра может быть
установлено в NULL.
 Параметр lpTotalBytesAvail должен указывать на переменную типа DWORD, в
которую функция записывает количество доступных для чтения байтов,
находящихся в именованном канале. Если данные из именованного канала не
читаются, то значение этого параметра может быть установлено в NULL.
Если данные передаются потоком, а не сообщениями, то функция PeekNamedPipe читает
ровно столько байтов данных, какова длина буфера данных. Если же данные передаются
сообщениями, то функция читает полностью сообщение, которое входит в буфер данных.
В противном случае читается часть сообщения, а количество непрочитанных байтов возвращается через переменную, на которую указывает параметр lpBytesLeftThisMessage.
Пример копирования сообщения клиентом именованного канала:
Сначала проанализируйте программу процесса-сервера, в этой программе сначала создается именованный канал, затем производится подключение клиента, затем вводится строка сообщения для клиента, эта строка отображается на экране:
#include <windows.h>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
HANDLE hNamedPipe;
SECURITY_ATTRIBUTES sa; // атрибуты безопасности
SECURITY_DESCRIPTOR sd; // дескриптор безопасности
DWORD dwBytesWrite;
// для количества записанных байтов
char pchMessage[80];
// для сообщения
int nMessageLength;
// длина сообщения
// инициализация атрибутов безопасности
sa.nLength = sizeof(sa);
8
7
sa.bInheritHandle = FALSE; // дескриптор канала ненаследуемый
// инициализируем дескриптор безопасности
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
// разрешаем доступ к именованному каналу всем пользователям
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
sa.lpSecurityDescriptor = &sd;
// создаем именованный канал для чтения и записи
hNamedPipe = CreateNamedPipe(
"\\\\.\\pipe\\demo_pipe",
// имя канала
PIPE_ACCESS_DUPLEX, // читаем из канала и пишем в канал
PIPE_TYPE_MESSAGE | PIPE_WAIT, // синхронная передача сообщений
1,
// максимальное количество экземпляров канала
0,
// размер выходного буфера по умолчанию
0,
// размер входного буфера по умолчанию
INFINITE, // клиент ждет связь бесконечно долго
&sa
// доступ для всех пользователей
);
// проверяем на успешное создание
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
cerr << "Create named pipe failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to exit.";
cin.get();
return 0;
}
// ждем, пока клиент свяжется с каналом
cout << "The server is waiting for connection with a client." << endl;
if(!ConnectNamedPipe(
hNamedPipe, // дескриптор канала
NULL
// связь синхронная
))
{
cerr << "Connect named pipe failed." << endl
<< "The last error code: "<<GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// вводим строку
cout << "Input a string: ";
cin.getline(pchMessage, 80);
// определяем длину строки
nMessageLength = strlen(pchMessage) + 1;
// отвечаем клиенту
8
8
if (!WriteFile(
hNamedPipe, // дескриптор канала
pchMessage, // адрес буфера для вывода данных
nMessageLength, // количество записываемых байтов
&dwBytesWrite, // количество записанных байтов
NULL
// передача данных синхронная
))
{
cerr << "Write file failed." << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// выводим посланное клиенту сообщение на консоль
cout << "The server sent the message to a client: "
<< endl << '\t' << pchMessage << endl;
// закрываем дескриптор канала
CloseHandle(hNamedPipe);
// завершаем процесс
cout << "Press any key to exit.";
cin.get();
return 0;
}
Программа процесса-клиента запрашивает имя компьютера в сети, нужно ввести имя
компьютера, например, L57c314pc2.pmpe.ru, затем программа клиента связывается с именованным каналом, проверяет ошибки связи, затем копирует информацию и выводит ее на
экран, затем читает это же сообщение и отображает на экране:
#include <windows.h>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char machineName[80];
char pipeName[80];
HANDLE hNamedPipe;
DWORD dwBytesRead;
// для количества прочитанных байтов
DWORD dwTotalBytesAvail; // количество байтов в канале
DWORD dwBytesLeftThisMessage; // количество непрочитанных байтов
char pchMessage[80]; // для сообщения
// вводим имя машины в сети, на которой работает сервер
cout << "Enter a name of the server machine: ";
cin >> machineName;
cin.get();
// подставляем имя машины в имя канала
8
9
wsprintf(pipeName, "\\\\%s\\pipe\\demo_pipe", machineName);
// связываемся с именованным каналом
hNamedPipe = CreateFile(
pipeName,
// имя канала
GENERIC_READ | GENERIC_WRITE, // читаем и записываем в канал
FILE_SHARE_READ | FILE_SHARE_WRITE, // разрешаем чтение и запись
NULL,
// безопасность по умолчанию
OPEN_EXISTING, // открываем существующий канал
FILE_ATTRIBUTE_NORMAL, // атрибуты по умолчанию
NULL);
// дополнительных атрибутов нет
// проверяем связь с каналом
if (hNamedPipe==INVALID_HANDLE_VALUE)
{
cerr << "Connection with the named pipe failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to exit.";
cin.get();
return 0;
}
// ждем команду на копирование сообщения из канала
cout << "Press any key to peek a message." << endl;
cin.get();
// копируем информацию из именованного канала
if (!PeekNamedPipe(
hNamedPipe,
// дескриптор канала
pchMessage,
// данные
sizeof(pchMessage), // размер данных
&dwBytesRead,
// количество записанных байтов
&dwTotalBytesAvail, // количество байтов в канале
&dwBytesLeftThisMessage // количество непрочитанных байтов
))
{
// ошибка чтения сообщения
cerr << "Peek named pipe failed: " << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// выводим полученное сообщение на консоль
if (dwTotalBytesAvail)
cout << "The peeked message: "
<< endl << '\t' << pchMessage << endl;
else
cout << "There is no mesage." << endl;
9
0
// теперь читаем сообщение из именованного канала
if (!ReadFile(
hNamedPipe,
// дескриптор канала
pchMessage,
// данные
sizeof(pchMessage), // размер данных
&dwBytesRead, // количество записанных байтов
NULL))
// синхронное чтение
{
// ошибка чтения
cerr << "Read file failed: " << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// выводим полученное сообщение на консоль
cout << "The client received the message from a server: "
<< endl << '\t' << pchMessage << endl;
// закрываем дескриптор канала
CloseHandle(hNamedPipe);
// завершаем процесс
cout << "Press any key to exit." << endl;
cin.get();
return 0;
}
Передача транзакций по именованному каналу
Для обмена сообщениями по сети может также использоваться функция TransactNamedPipe, которая объединяет операции записи и чтения в одну операцию, которая
называется транзакцией. Эта функция может использоваться только в том случае, если
сервер при создании именованного канала установил флаг PIPE_TYPE_MESSAGE. Функция TransactNamedPipe имеет следующий прототип:
BOOL TransactNamedPipe (
HANDLE hNamedPipe,
//дескриптор именованного канала
LPVOID lpInBuffer,
//буфер для записи в канал
DWORD dwInBufferSize,
//длина буфера для записи
LPVOID lpOutBuffer,
//буфер для чтения из канала
DWORD dwOutBufferSize,
//длина буфера для чтения
LPDWORD lpBytesRead,
//количество прочитанных байтов
LPOVERLAPPED lpOverlapped //асинхронный доступ к каналу
);
В случае успешного завершения функция возвращает ненулевое значение, в случае неудачи FALSE. Параметры функции имеют следующее назначение:
1. В параметре hNamedPipe должен быть установлен дескриптор именованного
канала.
2. Параметр lpInBuffer должен указывать на буфер, из которого записываются данные
в именованный канал.
3. Параметр dwInBufferSize должен содержать длину передаваемого сообщения в
9
1
байтах.
4. Параметр lpOutBuffer должен указывать на буфер, в который читаются данные из
именованного канала.
5. Параметр dwOutBufferSize должен содержать длину буфера, в который читается
сообщение
6. Параметр lpBytesRead должен указывать на переменную типа DWORD, в которую
функция поместит количество прочитанных байтов. Если осуществляется
асинхронный доступ к именованному каналу, то значение этого параметра можно
установить в NULL.
7. Параметр lpOverlapped используется в том случае, если осуществляется
асинхронный доступ к именованному каналу. В этом случае параметр должен
указывать на структуру типа OVERLAPPED. При синхронной передаче этот
параметр равен NULL.
Если клиент и сервер именованного канала работают на одном компьютере, то для
связи клиента с именованным каналом нужно вводить полное имя компьютера. Если
же вместо имени компьютера будет введена точка, то именованный канал откроется в
режиме передачи данных потоком, а не сообщениями, а это вызовет ошибку при передаче данных.
Для передачи единственной транзакции по именованному каналу используется функция CallNamedPipe, которая работает следующим образом. Сначала она связывается с
именованным каналом, используя его имя, причем именованный канал будет открыт в
режиме передачи данных сообщениями. Потом функция передает по именованному
каналу единственное сообщение и получает сообщение в ответ, а после этого разрывает связь с именованным каналом. Функция CallNamedPipe имеет следующий прототип:
BOOL CallNamedPipe (
LPCTSTR lpNamedPipeName,
//имя именованного канала
LPVOID lpInBuffer,
//буфер для записи данных в канал
DWORD dwInBufferSize,
//размер буфера для записи данных
LPVOID lpOutBuffer,
//буфер для чтения данных из канала
DWORD dwOutBufferSize,
//размер буфера для чтения данных
LPDWORD lpBytesRead,
//количество прочитанных байтов
DWORD dwTimeOut
//интервал ожидания
);
В случае успешного завершения функция возвращает ненулевое значение, в случае неудачи FALSE. Параметры функции:
1. Параметр lpNamedPipeName должен указывать на строку, содержащую имя
именованного канала.
2. Параметр lpInBuffer должен указывать на буфер, из которого записываются
данные в именованный канал.
8. Параметр dwInBufferSize должен содержать длину передаваемого сообщения в
байтах.
9. Параметр lpOutBuffer должен указывать на буфер, в который читаются данные из
именованного канала.
10. Параметр dwOutBufferSize должен содержать длину буфера, в который читается
сообщение
11. Параметр lpBytesRead должен указывать на переменную типа DWORD, в которую
функция поместит количество прочитанных байтов.
12. В параметре dwTimeOut должен быть установлен интервал ожидания в
миллисекундах, в течение которого функция ждет связи с именованным каналом.
Кроме того, можно установить следующие значения этого параметра:
a. NMPWAIT_NOWAIT – если нет свободного экземпляра именованного
канала, то функция немедленно возвращает управление;
9
2
b. NMPWAIT_WAIT_FOREVER – функция ждет бесконечно долго связи с
экземпляром именованного канала;
c. NMPWAIT_USE_DEFAULT_WAIT – интервал ожидания определяется
значением, заданными при создании именованного канала функцией
CreateNamedPipe.
Определение и изменение состояния именованного канала
Для получения информации о состоянии именованного канала используется функция
GetNamedPipeHandleState, которая имеет следующий прототип:
BOOL GetNamedPipeHandleState (
HANDLE hNamedPipe,
//дескриптор именованного канала
LPDWORD lpState,
//состояние канала
LPDWORD lpCurrentInstances,
//количество экземпляров канала
LPDWORD lpMaxCollectionCount, //максимальное количество байтов
LPDWORD lpCollectionDataTimeout,
//интервал ожидания
LPTSTR lpUserName,
//имя клиента именованного канала
DWORD dwMaxUserNameSize
//длина буфера для имени клиента
);
В случае успешного завершения функция возвращает ненулевое значение, в случае неудачи FALSE. Параметры функции:
1. В параметре hNamedPipe должен быть установлен дескриптор именованного
канала, причем канал должен быть открыт в режиме чтения.
2. Параметр lpState должен указывать на переменную типа DWORD, в которую
функция записывает любую комбинацию следующих значений:
a. PIPE_NOWAIT -канал не блокирован.
b. PIPE_READMODE_MESSAGE — канал открыт в режиме передачи данных
сообщениями.
Если значение PIPE_NOWAIT не установлено, то канал блокирован. Если не
установлено значение PIPE_READMODE_MESSAGE, то канал открыт в
режиме передачи данных потоком. Если определять состояние именованного
канала не нужно, то в параметре lpState может быть установлено значение
NULL.
3. Параметр lpCurrentInstances должен указывать на переменную типа DWORD, в
которую функция записывает количество созданных экземпляров именованного
канала.
4. Параметр lpMaxCollectionCount должен указывать на переменную типа DWORD,
в которую функция запишет максимальное количество байтов, которые клиент
именованного канала должен записывать в этот канал, прежде чем данные будут
переданы серверу канала. Этот параметр должен быть установлен в NULL, если
функция вызывается сервером именованного канала и если клиент и сервер
работают на одном компьютере и для связи с сервером клиент использует «.»
вместо имени сервера.
5. Параметр lpCollectionDataTimeout должен указывать на переменную типа DWORD,
в которую функция поместит количество миллисекунд, которые могут пройти,
прежде чем данные могут быть переданы по сети.
6. Параметр lpUserName должен указывать на символьный массив, в который
функция поместит строку с именем владельца именованного канала. Имя
владельца можно получить только в том случае, если доступ к каналу открыт всем
пользователям
9
3
Параметр dwMaxUserNameSize должен содержать размер области памяти, на
которую указывает параметр lpUserName.
Изменить некоторые характеристики именованного канала можно функцией
SetNamedPipeHandleState, которая имеет следующий прототип:
BOOL SetNamedPipeHandleState (
HANDLE hNamedPipe,
//дескриптор именованного канала
LPDWORD lpMode,
//новый режим передачи данных
LPDWORD lpMaxCollectionCount,//максимальное количество байтов
LPDWORD lpCollectionDataTimeout//интервал ожидания
);
В случае успешного завершения функция возвращает ненулевое значение, в случае неудачи FALSE. Параметры функции:
8. В параметре hNamedPipe должен быть установлен дескриптор именованного
канала, причем канал должен быть открыт в режиме записи.
9. Параметр lpMode должен указывать на переменную типа DWORD, которая
содержит новые режимы работы именованного канала. Возможно изменить
следующие режимы работы именованного канала: режим передачи данных и
режим ожидания при выполнении записи или чтении данных в именованный канал,
а также ожидания сервером соединения клиента с именованным каналом. Режим
передачи данных может принимать следующие значения:
a. PIPE_READMODE_BYTE — передача данных потоком.
b. PIPE_READMODE_MESSAGE — передача данных сообщениями.
Режим ожидания может принимать следующие значения:
c. PIPE_WAIT — блокирование приложения до завершения выполнения функций
ConnectNamedPipe, WriteFile, ReadFile.
d. PIPE_NOWAIT -выполнение функций ConnectNamedPipe, WriteFile и ReadFile
не блокирует работу приложения.
Эти режимы ожидания не влияют на работу асинхронных операций доступа к именованному каналу, они предназначены только для работы менеджера локальной сети. В параметре lpMode может быть установлена любая комбинация флагов режимов передачи данных и ожидания или только один из этих флагов. Если режимы работы именованного канала не изменяются, то параметр lpMode должен содержать значение NULL.
6 Параметр lpMaxCollectionCount должен указывать на переменную типа DWORD,
которая содержит максимальное количество байтов, которые клиент именованного
канала может записать в этот канал, прежде чем эти данные будут переданы
серверу канала. Но если клиент открыл именованный канал в режиме
FILE_FLAG_WRITE_THROUGH, то параметр lpMaxCollectionCount
игнорируется. Этот параметр может быть установлен в NULL, если функция не
изменяет размер максимального количества записываемых перед передачей байтов.
7 Параметр lpCollectionDataTimeout должен указывать на переменную типа
DWORD, которая содержит новое количество миллисекунд, которые должны
пройти, прежде чем данные могут быть переданы по сети. Если клиент открыл
именованный канал в режиме FILE_FLAG_WRITE_THROUGH, то этот параметр
игнорируется.
Для получения информации об атрибутах именованного канала, которые не могут быть
изменены, используется функция GetNamedPipeInfo, имеющая следующий прототип:
BOOL GetNamedPipeInfo (
HANDLE hNamedPipe,
//дескриптор именованного канала
LPDWORD lpFlags,
//тип канала
LPDWORD lpOutBufferSize,
//размер выходного буфера
7.
9
4
LPDWORD lpInBufferSize,
//размер входного буфера
LPDWORD lpMaxInstances
//макс. количество экземпляров канала
);
В случае успешного завершения функция возвращает ненулевое значение, в случае неудачи FALSE. Параметры функции:
2. В параметре hNamedPipe должен быть установлен дескриптор именованного
канала, причем канал открыт в режиме чтения.
3. Параметр lpFlags должен указывать на переменную типа DWORD, в которой
установлен тип именованного канала, о котором нужно получить информацию.
Тип именованного канала должен содержать информацию о способе передачи
данных по каналу и указывать, кому принадлежит дескриптор: клиенту или
серверу. Для этого должны использоваться следующие константы:
1. PIPE_CLIENT_END — дескриптор клиента именованного канала.
2. PIPE_SERVER_END — дескриптор сервера именованного канала.
3. PIPE_TYPE_BYTE — передача данных потоком.
4. PIPE_TYPE_MESSAGE - передача данных сообщениями.
Если эта информация не установлена, т.е. параметр lpFlags имеет значение NULL,
то функция рассматривает тот конец именованного канала, который соединен с
клиентом, и по которому данные передаются потоком.
4. Параметр lpOutBufferSize должен указывать на переменную типа DWORD, в
которую функция поместит размер выходного буфера именованного канала. Если
информация о буфере не нужна, то значение этого параметра может быть
установлено в NULL.
5. Параметр lpInBufferSize должен указывать на переменную типа DWORD, в
которую функция поместит размер входного буфера именованного канала. Если
информация о буфере не нужна, то значение этого параметра может быть
установлено в NULL.
6. Параметр lpMaxInstances должен указывать на переменную типа DWORD, в
которую функция поместит число, обозначающее максимальное допустимое
количество экземпляров именованного канала. Если это число равно значению
PIPE_UNLIMITED_INSTANCES, то количество экземпляров именованного канала
ограничено только наличием системных ресурсов. Если информация о
максимальном количестве экземпляров именованного канала не нужна, значение
этого параметра может быть установлено в NULL.
Задание
№ 1. Создайте программу процесса-сервера именованного канала, который сначала создает именованный канал, затем ждет подключения к нему клиента. После этого сервер принимает от клиента одно сообщение, выводит это сообщение на консоль и посылает клиенту ответное сообщение. Атрибуты безопасности должны быть установлены таким образом, чтобы они разрешали доступ к именованному любому пользователю. Создайте программу клиента именованного канала, который сначала вводит с консоли имя компьютера в локальной сети, на котором запущен сервер именованного канала, а затем клиент передает серверу сообщение.
№ 2. Создайте программу процесса-клиента именованного канала, которая передает транзакцию, используя функцию TransactNamedPipe. Получите информацию о канале.
Контрольные вопросы
1. Чем отличается использование именованных каналов от анонимных?
2. Как выполняется работа с именованными каналами?
3. Как получить информацию о параметрах именованного канала?
9
5
4. Как выполнить копирование данных из именованного канала?
Лабораторная работа № 5 (2 часа)
Тема: Структурная обработка исключений
Цель:
Краткие теоретические сведения
Исключением называется событие, которое произошло во время выполнения программы., в результате совершения которого дальнейшее нормальное выполнение становится невозможным.
Для восстановления программы в рабочее состояние в ОС Windows предназначен механизм
структурной обработки исключений (SEN). В программе выделяется блок программного кода, в
котором может произойти исключение. Такой блок называется фреймом, а сам код называется
охраняемым кодом. Затем, после фрейма вставляется программный код который обрабатывает
происшедшее исключение. Ключевое слово __try отмечает фрейм. Ключевое слово __except отмечает обработчик исключения.
Получить код происшедшего исключения можно при помощи функции GetExceptionCode. По возвращаемому значению производится соответствующая обработка возникшей ошибки.
Задание
№1. Создайте приложение, в котором функция GetExceptionCode вызывается в выражении
фильтра и используется для проверки того, что нужно ли передавать управление текущему блоку
обработки исключений или продолжить поиск другого обработчика.
№ 2. Создайте приложение, в котором на консоль выводится информация об исключении. Информация об исключении получается функцией GetExceptionInformation.
№ 3. Создайте приложение, которое генерирует программное исключение RaiseException и передает функции фильтра два параметра.
№ 4. Создайте приложение, в котором обрабатывается исключение с плавающей точкой при делении на ноль.
№ 5. Создайте приложение, в котором используется обработка вложенных исключений.
Контрольные вопросы
1 Какие значения возвращаются функцией GetExceptionCode?
2 Где вызывается функция GetExceptionCode?
3 Какие параметры используются в функции RaiseException?
4 Что происходит, если в программе произошло исключение, для которого не существует обработчика исключений?
5 Как включить режим генерации исключений с плавающей точкой?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
9
6
Лабораторная работа № 6-1 (2 часа)
Тема: Работа с виртуальной памятью
Цель: Изучить работу с виртуальной памятью
Краткие теоретические сведения
Резервирование, распределение и освобождение виртуальной памяти
Под логической памятью процесса понимается массив байтов, к которым может обратиться процесс. Индекс каждого элемента массива называется логическим адресом. Так как
логическая память процесса представляется линейным массивом байтов, то логический
адрес процесса обычно называют линейным адресом. Линейный адрес процесса в Windows, обычно, состоит из 32 бит и изменяется в пределах от 0х00000000 до 0хFFFFFFFF .
Это теоретически позволяет процессу обращаться к 4 Гбайт логической памяти. Во время
работы процесса необходимо отображать логическую память процесса в физическую память компьютера. Обычно прямое отображение невозможно, так как объем логической
памяти процесса превышает объем физической памяти. Для решения этой задачи физическую память компьютера дополняют памятью на дисках. Полученную расширенную память называют виртуальной памятью, а адрес элемента этой памяти называют виртуальным адресом. Преобразование линейного адреса процесса в виртуальный адрес выполняется операционной системой посредством настройки регистров процессора. Преобразование виртуального адреса в физический адрес выполняется аппаратно (процессором).
Для реализации преобразования виртуального адреса в физический, виртуальную память
делят на блоки одинаковой длины, обычно равной 4Кбайт, которые называют страницами.
При обращении процесса по адресу в виртуальной странице, если необходимо, то происходит загрузка этой страницы в реальную память компьютера и настройка адресного пространства процесса на работу с этой страницей. Учитывая страничную организацию виртуальной памяти, фактически адрес делится на две части: старшую и младшую. Старшая
часть адреса рассматривается как номер страницы в реальной или виртуальной памяти,
младшая часть – как смещение внутри этой страницы. Для преобразования виртуальных
адресов в реальные адреса в системной области физической памяти для каждого процесса
хранится таблица страниц. Адрес таблицы страниц хранится в
специальной таблице, называемой каталогом таблиц страниц.
Страницы виртуальной памяти процесса могут находиться в одном из трех состояний:
свободны для использования (free);
распределены процессу для использования (committed);
зарезервированы, но не используются процессом (reserved);
Для резервирования или распределения области виртуальной памяти процесс должен вызвать функцию VirtualAlloc, которая имеет следующий прототип:
LPVOID VirtualAlloc (
LPVOID lpAddress,
//область для распределения и резервирования
SIZE_T dwSize,
//размер области
DWORD flAllocationType, //тип распределения
DWORD flProtect
//тип защиты доступв
);
В случае успешного завершения эта функция возвращает адрес виртуальной памяти, распределенной или зарезервированной процессом (выделенная память автоматически инициализируется нулями), в случае неудачи – NULL.
Назначение параметров:
9
7
6.Параметр lpAddress устанавливается вызывающей программой и указывает системе
начальный адрес виртуальной памяти, которую процесс хочет зарезервировать или
распределить. Этот адрес
может указывать как на свободную, так и на
зарезервированную ранее виртуальную память. При этом, в случае резервирования
виртуальной памяти этот адрес выравнивается системой до границы в 64Кбайт,
которая предшествует указанному адресу, в случае распределения виртуальной памяти
из зарезервированной ранее области этот адрес округляется ОС до границы
виртуальной страницы, содержащей этот адрес.
7.Параметр dwSize . устанавливается вызывающей программой и указывает размер
распределяемой или резервируемой области виртуальной памяти в байтах. Если
параметр lpAddress равен NULL, то система округляет эту величину в большую
сторону до кратности размеру виртуальной страницы. Если же память распределяется
по конкретным адресам, то эта память будет включать все страницы от lpAddress до
lpAddress+ dwSize.
8.Параметр flAllocationType устанавливается
программой и указывает на тип
операции, которую выполняет функция VirtualAlloc. Значением этого параметра может
быть любая комбинация следующих флагов:
1.MEM_COMMIT – распределить память программе;
2.MEM_RESERVE –зарезервировать область физической памяти
В ОС Windows NT5 этом параметре могут устанавливаться следующие флаги:
MEM_RESET –память временно не используется;
MEM_TOP_DOWN –распределить память, начиная с наибольшего из
свободных адресов.
Параметр flProtect устанавливает атрибуты доступа к области виртуальной памяти,
которые разрешают выполнять над страницами виртуальной памяти только
определенные операции:
PAGE_READONLY –разрешает только чтение виртуальных страниц;
PAGE_READWRITE –разрешает чтение и запись в виртуальных страницах;
PAGE_EXECUTE – разрешает только исполнение кода в виртуальных страницах;
PAGE_EXECUTE_READ –разрешает исполнение и чтение кода в виртуальных
страницах;
PAGE_EXECUTE_READWRITE –разрешает выполнение, чтение, и запись
виртуальных страниц;
PAGE_NOACCESS –к виртуальным страницам нет доступа;
PAGE_NOCACHE –виртуальные страницы можно не помещать в кэш;
PAGE_GUARD - охраняемая страница. Это т флаг используется для определения
момента, когда процессу необходимо выделить дополнительную виртуальную
память. Этот флаг не может быть использован совместно с флагом
PAGE_NOACCESS.
После завершения работы с виртуальной памятью ее необходимо освободить , используя
функцию VirtualFree, которая имеет следующий прототип:
BOOL VirtualFree (
LPVOID lpAddress,
// адрес области виртуальной памяти
SIZE_T dwSize,
// размер области
DWORD dwFreeType
//тип операции
);
В случае успешного завершения эта функция возвращает ненулевое значение, в случае
неудачи - NULL.
Назначение параметров:
Параметр lpAddress должен указывать на базовый адрес области, для которой нужно
отменить распределение или освободить. Если в параметре dwFreeType установлен
9
8
флаг MEM_RELEASE, то этот адрес должен совпадать с адресом , который
возвратила, функция VirtualAlloc.
Параметр dwSize задает в байтах размер области виртуальной памяти, распределение
которой нужно отменить.
Если в параметре dwFreeType установлен флаг
MEM_RELEASE, то значение параметра dwSize должно быть равно нулю.
Блокирование виртуальных страниц в реальной памяти
Если некоторая область виртуальной памяти будет часто использоваться процессом, то
можно запретить системе выгружать эти виртуальные страницы из реальной памяти (заблокировать). Для этого используется функция:
BOOL VirtualLock (
LPVOID lpAddress,
//адрес области
SIZE_T dwSize
//размер области
);
При успешном завершении функция возвращает ненулевое значение, а в случае неудачи FALSE.
Параметры lpAddress и dwSize указывают соответственно, базовый адрес и размеры области, которая запирается в реальной памяти. Нельзя запирать в реальной памяти виртуальные страницы, к которым доступ запрещен (установлен флаг PAGE_NOACCESS). Кроме
того, ОС не позволяет процессу блокировать в реальной памяти более 30 виртуальных
страниц сразу.
Для отмены блокировки виртуальных страниц в реальной памяти используется функция
VirtualUnlock, которая имеет следующий прототип:
BOOL VirtualUnlock (
LPVOID lpAddress,
// адрес области
SIZE_T dwSize
//размер области
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи - FALSE. Павраметы имеют такое же назначение, как и у функции VirtualLock.
При этом до вызова функции VirtualUnlock
диапазон адресов от lpAddress до
lpAddress+dwSize должен быть предварительно блокирован функцией VirtualLock. Если
это условие не выполняется , то ОС освобождает страницы из рабочего множества страниц процесса.
Изменение атрибутов доступа к виртуальной странице
Изменить атрибуты доступа к области виртуальной памяти можно при помощи вызова
функции VirtualProtect, которая имеет следующий прототип:
BOOL VirtualProtect (
LPVOID lpAddress,
//адрес области памяти
SIZE_T dwSize,
//размер области памяти
DWORD flNewProtect,
//флага новых атрибутов доступа
PDWORD lpflOldProtect //указатель на старые атрибуты доступа
);
В случае успеха функция возвращает значение, в случае неудачи - FALSE. Параметры
имеют то же назначение, что и у функции VirtualAlloc.
Управление рабочим множеством страниу процесса
Узнать о количестве страниц, которые входят в рабочее множество процесса, можно посредством вызова функции GetProcessWorkingSetSize, которая имеет следующий прототип:
BOOL GetProcessWorkingSetSize (
HANDLE hProcess,
//дескриптор процесса
PSIZE_T lpMinWorkingSetSize, //мин. Размер рабочего множества
PSIZE_T lpMaxWorkingSetSize
//макс. Размер рабочего множества
);
9
9
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи - FALSE. При вызове этой функции в параметре hProcess должен быть установлен дескриптор процесса, для которого требуется узнать диапазон рабочего множества
страниц. При успешном завершении функция GetProcessWorkingSetSize возвращает по
адресам, заданным в параметрах lpMinWorkingSetSize и lpMaxWorkingSetSize, соответственно минимальный и максимальный размеры рабочего множества станиц процесса.
При работе процесса менеджер виртуальной памяти поддерживает количество виртуальных страниц, распределенных процессу, в этом диапазоне.
Минимальный и максимальный размеры рабочего множества страниц процесса можно
изменить посредством вызова функции SetProcessWorkingSetSize, которая имеет следующий прототип:
BOOL SetProcessWorkingSetSize (
HANDLE hProcess,
//дескриптор процесса
SIZE_T dwMinWorkingSetSize, //мин. размер рабочего множества
SIZE_T dwMaxWorkingSetSize //макс. размер рабочего множества
);
В случае успешного завершения эта функция возвращает ненулевое значение, а в случае
неудачи - FALSE.
Параметр hProcess содержит дескриптор процесса, для которого изменяется диапазон рабочего множества страниц. Параметры dwMinWorkingSetSize и dwMaxWorkingSetSize
устанавливаются в вызывающей программе. Если значения обоих этих параметров установлены в -1, то из рабочего множества страниц процесса удаляются все страницы.
Инициализация и копирование блоков виртуальной памяти
Чтобы заполнить блок памяти определенным значением, используется функция
FillMemory, которая имеет следующий прототип:
VOID FillMemory (
PVOID Destination,
// адрес блока памяти
SIZE_T Length,
// длина блока
BYTE Fill
// символ-заполнитель
);
Эта функция заполняет блок памяти, длина в байтах и базовый адрес которого задаются
соответственно параметрами Length и Destination, символом, заданным в параметре Fill.
Если блок памяти необходимо заполнить нулями, то для этого можно использовать функцию ZeroMemory, которая имеет следующий прототип:
VOID ZeroMemory(
PVOID Destination, // адрес блока памяти
SIZE_T Length );
// длина блока
Параметры этой функции имеют то же назначение, что и параметры функции FillMemory,
исключая символ-заполнитель.
Для копирования блока виртуальной памяти используется функция CopyMemory, которая
имеет следующий прототип:
VOID CopyMemory (
PVOID Destination,
// адрес области назначения
CONST VOID * Source,
// адрес исходной области
SIZE_T Length );
// длина блока памяти
Результат выполнения функции CopyMemory непредсказуем, если исходный и результирующий блоки памяти перекрываются.
Для копирования перекрывающихся блоков памяти используются функция MoveMemory,
которая имеет следующий прототип:
VOID MoveMemory (
PVOID Destination,
// адрес области назначения
CONST VOID * Source,
// адрес исходной области
1
0
0
SIZE_T Length );
// длина блока памяти
Определение состояния памяти
Определить состояние области виртуальной памяти процесса можно припомощи вызова
функции VirtualQuery:
DWORD VirtualQuery (
LPCVOID lpAddress,
// адрес памяти
PMEMORY_BASIC_INFORMATION lpBuffer, // буфер для информации
DWORD dwLength
// длина буфера
);
Параметр lpAddress указывает на область виртуальной памяти, информацию о которой
нужно получить. При этом размер области определяется количеством последовательных
виртуальных страниц, которые имеют одинаковые атрибуты. Параметр lpBuffer указывает на структуру типа MEMORY_BASIC_INFORMATION, в которую функция VirtualQuery поместит информацию об указанной параметром lpAddress области виртуальной
памяти.
Параметр dwLength должен содержать длину структуры, на которую указывает параметр
lpBuffer. После своего завершения функция VirtualQuery возвращает действительное количество байтов, записанных в структуру по адресу lpBuffer.
Структура типа MEMORY_BASIC_INFORMATION состоит из следующих полей:
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
//базовый адрес области виртуальной памяти
PVOID AllocationBase;
//базовый адрес распределенной памяти
DWORD AllocationProtect;
//атрибуты доступа к распределенной памяти
SIZE_T RegionSize;
// размер области с одинаковыми атрибутами
DWORD State;
// состояние памяти
DWORD Protect;
// атрибуты доступа к области виртуальной памяти
DWORD Type;
//тип страниц в области виртуальной памяти
} MEMORY_BASIC_INFORMATION, * PMEMORY_BASIC_INFORMATION;
Значения этих полей, кроме поля Type, совпадают со значениями параметров, которые
задаются в функциях для работы с виртуальной памятью. Существует только различие в
областях памяти, которые описывают эти поля. Различие между значениями полей Address и AllocationBase заключается в том, первое значение указывает на область виртуальной памяти, состояние которой нужно узнать, второе значение – на область виртуальной
памяти, которая была распределена функцией VirtualAlloc и содержит интересующую область.
Также существует различие между назначением полей AllocationProtect и Protect. Поле
AllocationProtect содержит атрибуты доступа к области памяти, распределенной функцией
VirtualAlloc, поле Protect - атрибуты доступа области виртуальной памяти, о которой
нужно получить информацию. Эти поля принимают те же значения, что и параметр flProtect при вызове функции VirtualAlloc.
Поле State принимает те же значения, что и параметр flAllocationType при вызове функции VirtualAlloc.
Поле Type описывает тип страниц в области виртуальной памяти, информация о которой
определяется. Это поле может принимать одно из следующих значений:
 MEM_IMAGE – исполняемый код;
 MEM_MAPPED – файл, проецируемый в память;
 MEM_PRIVATE – память, принадлежащая процессу.
Работа с виртуальной памятью в другом процессе
Для работы с виртуальной памятью в другом процессе существуют функции:
 VirtualAllocEx – распределить виртуальную память;
 VirtualFreeEx – освободить виртуальную память;
 VirtualProtectEx – изменить атрибуты доступа;
1
0
1
 VirtualQueryEx –определить состояние области.
Список параметров этих функций отличается, от рассмотренных выше функций без
суффикса Ex, только первым дополнительным параметром –дескриптором процесса, с
адресным пространством которого работает функция.
Функция ReadProcessMemory предназначена для чтения данных из виртуальной памяти другого процесса. Она имеет следующий прототип:
BOOL ReadProcessMemory (
HANDLE hProcess,
// дескриптор процесса
LPCVOID lpBaseAddress, // базовый адрес области
LPVOID lpBuffer,
// буфер данных
DWORD nSize,
// количество считываемых байт
LPDWORD lpNumberOfBytes //количество прочитанных байт
);
Функция WriteProcessMemory предназначена для записи данных в виртуальную память другого процесса. Она имеет следующий прототип:
BOOL WriteProcessMemory (
HANDLE hProcess,
// дескриптор процесса
LPCVOID lpBaseAddress, // базовый адрес области
LPVOID lpBuffer,
// буфер данных
DWORD nSize,
// количество записываемых байт
LPDWORD lpNumberOfBytes //количество записанных байт
);
Эти функции в случае успешного завершения возвращают ненулевое значение, в противном случае – FALSE. Назначение параметров:
 Параметр hProcess должен содержать дескриптор процесса, к виртуальной
памяти которого обращается функция.
 Параметр lpBaseAddress должен указывать на область виртуальной памяти,
которой обращается функция.
 Параметр
lpBuffer указывает на область памяти, в которую функция
ReadProcessMemory будет читать данные из виртуальной памяти другого
процесса, а функция WriteProcessMemory записывать данные в виртуальную
память другого процесса.
 Параметр nSize должен содержать количество байтов, которые функция
ReadProcessMemory читает из виртуальной памяти другого процесса, а функция
WriteProcessMemory записывает в виртуальную память другого процесса.
 Параметр lpNumberOfBytes должен указывать на двойное слово, в которое
вызываемая функция поместит количество прочитанных или записанных байт.
Этот параметр может быть установлен в значение NULL и тогда вызываемая
функция игнорирует его.
Задание.
№1 . Создайте приложение, в котором распределяется виртуальная память для целочисленного массива размерностью 1500. Доступ позволяет чтение и запись. Затем эта виртуальная память должна быть освобождена.
№ 2. Создайте приложение, в котором виртуальная память необходимыи объемом распределялась по конкретному адресу.
№ 3. Создайте приложение, в котором память распределяется в два этапа. Сначала резервируется область виртуальной памяти, а затем распределяется некоторая часть этой виртуальной памяти. Измените программу и покажите использование флага доступа к охраняемой странице.
1
0
2
№ 4. Создайте приложение, в котором используется блокирование и разблокирование
виртуальных страниц в реальной памяти. Поясните, для чего требуется блокировка.
№ 5. Создайте приложение, в котором изменяются атрибуты доступа к виртуальной странице, Например, сначала допустимо только чтение, а изменение невозможно, а затем после изменения атрибутов, возможно и изменение рабочего множества виртуальных страниц.
№ 6. Создайте два приложения. Первое приложение создает консольный процесс, а затем
пишет и читает данные из виртуальной памяти этого процесса. Адрес виртуальной памяти, по которому дочерний консольный процесс должен записать ответное сообщение, передается этому процессу через командную строку. Оба приложения синхронизируют свой
доступ к виртуальной памяти, чтобы корректно передать и получить сообщения.
Контрольные вопросы
1. Объясните понятие виртуальной памяти
2. Как организована виртуальная память?
3. Как определить состояние области виртуальной памяти?
4. Как выделяется память для резервирования или распределения памяти?
5. Как заблокировать виртуальные страницы в реальной памяти?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная работа № 6-2
Тема: Работа с кучей в Windows
Цель: Изучить использование функций для работы с кучей
Краткие теоретические сведения
Кучей называется распределенная процессом область виртуальной памяти, используемая
им для захвата или освобождения блоков памяти , размер которых меньше размера виртуальной страницы. Куча называется сериализуемой, если система синхронизирует доступ
параллельно работающих потоков к этой куче. Для динамического создания кучи используется функция HeapCreate. Для уничтожения кучи нужно использовать функцию
HeapDestroy. Для распределения памяти из кучи используется функция HeapAlloc.
Задание
1
0
3
№1. Создайте приложение, в котором реализовано динамическое создание кучи под массив типа double (размерность массива 800-1000).
№ 2. Создайте приложение, в котором распределяется и освобождается память из кучи
процесса.
№ 3. Создайте приложение, в котором используется блокирование и разблокирование кучи, проверяется состояние кучи.
№ 4. Создайте приложение, в котором динамически создается куча, затем в ней распределяется память под четыре массива (размерность не меньше 1000). Проверяется свободное
место в куче, освобождаются первых два или массива, затем куча уплотняется.
№ 5. Создайте приложение, реализующее преобразование файла с использованием метода отображения файлов
Контрольные вопросы
.1Как получить информацию о состоянии кучи?
.2 Какую функцию используют для уплотнения кучи?
.3Как заблокировать параллельный доступ нескольких потоков к куче?
.4Как перераспределить память из кучи?
.5 Какие атрибуты защиты страниц можно установить?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная рвабота № 7 (2 часа)
. Тема: Динамически подключаемые библиотеки. Динамическая локальная память потока
Цель: Изучить функции использования локальной памяти потока
Краткие теоретические сведения
Динамическая локальная память потока TLS представляет собой массив указателей, доступ к ккоторым осуществляется через индексы при помощи специальных функций Win32 API. Порядок работы с локальной памятью потока следующий:

распределние указателя;

работа с указателем;
1
0
4

освобождение указателя;
Прежде чем использовать какой-либо указатель, его нужно распределить. Это делается при помощи функции TlsAlloc. После распределения указателя для каждого потока становится доступной
своя копия этого указателя. Для работы с указателями локальной памяти потока используются
функции TlsSetValue и TlsGetValue, которые соответственно записывают некоторое значение и
читают значение из локальной памяти потока. После окончания работы с указателем его нужно
освободить, вызвав функцию TlsFree.
Задание
№ 1. Создайте многопоточное приложение, в котором одновременно выполняется поиск текстового шаблона в нескольких файлах. Код функции поиска основан на вызовах функций файлового
ввода-вывода из динамической библиотеки.
Контрольные вопросы
1.Для чего используется динамическая локальная память потока?
2.Каков порядок работы с локальной памятью потока?
3.Каким образом выполняется запись и чтение из локальной памяти потока?
4.Каким образом реализовать статическую локальную память потока?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лабораторная работа № 8 (4 часа)
Тема: Асинхронная обработка данных
Цель: Изучить использование функций асинхронной обработки данных
Краткие теоретические сведения
Порты завершения ввода-вывода , поддерживаемые лишь на NT-платформах, объединяют в себе
возможности перекрывающегося ввода-вывода и независимых потоков.и используются чаще всего
1
0
5
в серверных программах. Использование портов завершения ввода-вывода предоставлет возможность создавать ограниченное количество серверных потоков в пуле потоков. Порт завершения ввода-вывода –это набор перекрывающихся дескрипторов, и потоки ожидают перехода порта в сигнальное состояние. Когда завершается операция чтения или записи с участием какого-либо
дескриптора, один из потоков пробуждается и принимает данные и результаты выполнения операции ввода-вывода. Далее поток может принимать данные и вновь перейти в состояние ожидания перехода порта в сигнальное состояние.
Задание
№1. Создайте приложение , реализующее асинхронный ввод-вывод для слияния несколь-
ких отсортированных файлов в один отсортированный большего размера.
№ 2. Создайте приложение многопоточного сервера на основе именованного канала, использующего порт завершения ввода-вывода. Выполните эксперименты с большим пулом потоков, чтобы выяснить эффективность этого варианта программного решения.
№ 3. Создайте программу клиента на основе именованного канала, введя в нее перекрывающийся ввод-вывод.
Контрольные вопросы
С какой целью рекомендуется использовать порты завершения ввода-вывода?
какая функция используется для создания порта завершения ввода-вывода? Объясните
назначение параметров этой функции.
Какая функция используется для посылки пакета в порт зпвершения?
Как создать и установить ожидающий таймер?
Литература
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
1
0
6
1.8. Учебно-методическое обеспечение дисциплины
1.8.1. Рекомендуемая литература
Основная
1. Аладьев В.З., Богдявичюс М.А. Maple 6: решение математ., статист. и инж-физ задач . М.: Лаборатория базовых знаний, 2001
2. Благодатских В.А., Волнин В.А., Поскакалов К.Ф. Стандартизация разработки программных средств: учеб. пособие для студ.вузов – М.: Финансы и статистика,2003
гриф
3. Ботт Э.,Зихерт К. Windows XP – СПб: Питер, 2004
4. Маккарти, Д. Правила разработки программного обеспечения/Д. Маккарти, М.
Маккарти, пер. с англ.- М.; Спб.: Русская редакция; Питер, 2007
5. Молчанов А. Ю. Системное программное обеспечение: Учебник для студ. вузов. –
СПб.: Питер, 2005. гриф
6. Гордеев А.В., Молчанов А.Ю. Системное программное обеспечение: учеб. для
студ.вузов – СПб: Питер, 2003 гриф
7. Молчанов А. Ю. Системное программное обеспечение. Лабораторный практикум:
Учебное пособие для вузов. – СПб.: Питер, 2005. гриф
8. Гордеев, А. В. Операционные системы: учебник для вузов- Изд. 2-е - СПб. : Питер,2007.гриф
9. Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual
C++ 6.0 – СПб: Питер; М.: Рус. Редакция, 2003
10. Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual
C++ 6.0 – СПб: Питер; М.: Рус. Редакция, 2004
11. Голоскоков, Д. П. Уравнения математической физики. Решение задач в системе
Maple.:учебник для вузов.- СПб.: Питер, 2004.
12. Матросов А,В., Чаунин М.П. Perl. Программирование на языке высокого уровня:
учеб. для студ.вузов – СПб: Питер, 2003 гриф
13. Панкратова, Т. В. Photoshop CS: учебный курс- СПб.: Питер, 2004.+ CD.
14. Молчанов А.Ю, Системное программное обеспечение: учеб. для студ.вузов – СПб:
Питер, 2003 гриф
15. Таненбаум, Э. Современные операционные системы- 2-е изд.- СПб.: Питер, 2006
16. Орлов С.А. Технологии разработки программного обеспечения: разработка сложных программных систем: учеб. пособие для студ.вузов – СПб: Питер, 2002 гриф
17. Соколов А.П. Системы программирования: теория, методы, алгоритмы:
учеб.пособие для студ.вузов – М.: Финансы и статистика, 2004 гриф
18. Андреев А. Microsoft Windows XP.Руководство администратора./ А. Г. Андреев [ и
др.] – СПб: БХВ – Петребург, 2006
19. Магда, Ю. А. Аппаратное обеспечение и эффективное программирование- Спб.:
Питер, 2007
20. Соловьев, М. М. 3 DS MAX 7 и 8 .Волшебный мир графики: с 2- мя компакт дисками- М.: Солон- Пресс, 2006
21. Шалин П.А. Реестр Windows XP: специальный справочник – СПб: Питер, 2005
22. Шалин П.А. Энциклопедия Windows XP:рус. И англ. Версии:наиболее полное и
подробное руководство – СПб: Питер, 2004
23. Миллхолон, М.Эффективная работа: Microsoft Office Word 2003/ М. Миллхолон,К.
Мюррей- Спб.: Питер,2005
24. Солоницин, Ю. А. Windows XP. Только практика/ Ю. А. Солоницин.- Спб.: Питер,
2006
1
0
7
Дополнительная.
1. Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++
6.00 для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом
«Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
3. Рихтер Дж. Windows для профессионалов: создание эффективных Win32приложений с учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е
изд.-СПб:Питер; М.:Издательско-торговый дом «Русская редакция», 2001.-752
стр.:ил. ISBN 5-272-00384-5
4. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека
программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
5. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы построения трансляторов./Учебное пособие для высших и средних учебных заведений.-СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
6. Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург,
2000-528 с.:ил.
1.9. Материально-техническое обеспечение дисциплины
Программное обеспечение:
Microsoft Visual Studio.Net 2005
1.9.1. Перечень используемых технических средств
Компьютеры на базе процессора
– Intel Pentium 4 2.8 Гц, 512 МВ ОЗУ;
– Intel Core 2 Duo 1.8 Гц, 1024 МВ ОЗУ.
1.9.2. Перечень используемых пособий
1.9.3. Перечень видео- и аудиоматериалов, программного обеспечения:
Microsoft Visual Studio.Net 2005
1.10. Примерные зачетные тестовые задания по дисциплине
1.Приведите программный код вывода на экран текущего каталога (функция Win32 API)
2. Напишите программный код создания двух каталогов, удаление одного из них.
3. Напишите программный код создания файла для записи данных, с монопольным
доступом, без защиты, с обычными атрибутами, без шаблона
4. Напишите программу, открывающую файл для чтения и записи, с разделяемым
доступом
5. Напишите программу, удаляющую файл
6. Напишите программу, записывающую в файл вводимые строки, используя функцию
WriteFile в синхронном режиме
7. Напишите программу, читающую из файла строки, используя функцию ReadFile
8. Напишите программу, копирующую, перемещающую файл и замещающую файл.
1
0
8
9. Напишите программу, которая позволяет по заданной позиции указателя прочитать
содержмиое.
10. Напишите программу, изменяющую атрибут файла с нормального на скрытый.
11. Напишите программу, определяющую и изменяющую размер файла
12. Напишите программу, позволяющую блокировать часть файла
13. Напишите программу, позволяющую определить тип файла
14. Напишите программу, в которой создается новый поток, вычисляющий простые числа
до указанного целого чила.
15. Реализуйте функцию приостановки потокови их возобновления
16. Создайте консольное приложение, в котором создается процесс с новой консолью
17. Напишите программу, позволяющую получить приоритет текщего потока, а также
изменить этот приоритет
18. Напишите программу, в которой создается критическая секция, выполняется вход в
нее и затем после выполнения вычислений выполняется выход из критической секции
19. Создайте приложение, реализующее функцию ожидания
20. Напишите приложение, создающее объект ядра мьютекс и выполните
синхронизацию потоков при помощи мьютексов
21. Напишите приложение, создающее объект ядра событие и выполните
синхронизацию потоков при помощи событий
22. Напишите приложение, создающее объект ядра семафор и выполните
синхронизацию потоков при помощи семафоров
23. Создайте программы процесса-сервера анонимного канала и процесса-клиента
анонимного канала. Объясните работу анонимного канала
24. Создайте программы процесса-сервера именованного канала и процесса-клиента
именованного канала. Объясните работу именнованного канала
25. Создайте программу процесса-сервера почтового ящика
26. Создайте программу процесса-клиента почтового ящика
27. Создайте программу, в которой резервируется и распределяется виртуальная память
28.
1.11. Примерный перечень вопросов к зачету
10. Примерный перечень вопросов к зачету
1. Классификация программного обеспечения. Системное программное обеспечение.
2. Понятие операционной среды. Основные принципы построения операционных систем.
3. Объекты ядра Windows. Диспетчер системных вызовов.
4. Категории функций API. Защита объектов ядра
5. Внутреннее устройство объектов ядра.
6. Основные типы объектов ядра. Дескрипторы объектов. Создание объектов ядра,
закрытие объектов ядра.
7. Совместное использование объектов ядра несколькими процессами.
8. Процессы. Состав процесса. Основные понятия. Описатель экземпляра процесса.
9. Функция создания процесса CreateProcess, ее параметры. Завершение процесса.
10. Дочерние процессы. Запуск обособленных дочерних процессов.
11. Базовые сведения о потоках. Создание потока функция CreateThread, ее параметры. Внутреннее устройство потока.
12. Планирование потоков, приоритет и привязка к процессорам.
1
0
9
13. Приостановка и возобновление потоков. Переключение потоков. Определение периодов выполнения потока. Структура CONTEXT.
14. Приоритеты потоков. Абстрагирование приоритетов. Программирование приоритетов. Динамическое изменение уровня приоритета потока.
15. Синхронизация потоков. Синхронизация потоков в пользовательском режиме: использование семейства Interlocked-функций и критических секций.
16. Синхронизация потоков с использованием объектов ядра:
17. Использование объекта ядра событий.
18. Использование объекта ядра семафоров
19. Использование объекта ядра мьютексов.
20. Сравнение мьютексов и критических секций
21. Управление памятью. Виртуальное адресное пространство процесса. Разделы адресного пространства.
22. Выделение регионов в адресном пространстве. Передача региону физической памяти.
23. Атрибуты защиты страниц физической памяти. Выравнивание данных.
24. Исследование виртуальной памяти: использование функций GetSystemInfo(),
GlobalMemoryStatus(), VirtualQuery().
25. Использование памяти в приложениях. . Использование виртуальной памяти,
26. Резервирование региона, передача памяти зарезервированному региону, возврат
физической памяти и освобождение региона.
27. Изменение атрибутов защиты. Стек потока.
28. Проецируемые в память файлы. Проецирование в память EXE- и DLL-файлов.
29. Концепция механизма отображения файлов в память; Создание и открытие объекта, отображающего файл;
30. Отображение файла в память; Обмен данными между процессами через отображаемый в память файл; Сброс вида в файл
31. Статические данные разделяются несколькими экземплярами EXE или DLL.
32. Использование проецируемых в память файлов. Обработка больших файлов.
33. Совместный доступ процессов к данным через механизм проецирования.
34. Динамически распределяемая память. Стандартная куча процесса.
35. Дополнительные кучи в процессе. Создание и удаление кучи
36. Распределение и освобождение памяти из кучи. Проверка состояния кучи. Уплотнение кучи
37. Изменение размера кучи. Использование куч в программах на С++.
38. Динамически подключаемые библиотеки. Преимущества использования библиотек. DLL в адресном пространстве процесса.
39. Создание DLL модуля. Понятие экспорта и импорта.
40. Явная загрузка DLL и связывание идентификаторов. Явная выгрузка DLL. Явное
подключение экспортируемого идентификатора.
41. Отложенная загрузка DLL.
42. Статическая и динамическая локальная память потока. Динамическая локальная
память потока;
43. Распределение и освобождение локальной памяти потока; Запись и чтение из локальной памяти потока;
44. Статическая локальная память потока
45. Файловые системы. Основные понятия и концепции организации ввода/вывода в
ОС. Файловые системы FAT, VFAT, FAT32, NTFS. Особенности использования.
46. Программирование консольных приложений
47. Способы передачи данных между процессами. Передача сообщений. Синхронный
и асинхронный обмен данными. Буферизация
48. Работа с анонимными каналами
1
1
0
49. Работа с именованными каналами
50. Работа с почтовыми ящиками в Windows
51. Исключения и их обработчики. Получение кода исключения.
52. Генерация программных исключений. Необработанные исключения
53. Обработка вложенных исключений.
54. Использование объекта ядра ожидаемых таймеров. Встраивание SEN в механизм
исключений С++. Финальная обработка исключений
55. Механизм асинхронного вызова процедур;
56. Установка асинхронных процедур; Приостановка потока; Ожидание события;
57. Оповещение и ожидание события;
58. Концепция асинхронного ввода-вывода;
59. Асинхронная запись данных;
60. Блокирование файлов;
61. Определение состояния асинхронной операции ввода-вывода;
62. Отмена асинхронной операции ввода-вывода;
63. Процедуры завершения ввода-вывода;
64. Асинхронная запись данных с процедурами завершения;
65. Асинхронное чтение данных с процедурами завершения;
66. Концепция порта завершения; Создание порта завершения; Получение пакета из
порта завершения;
67. Создание и открытие ожидающего таймера; Установка ожидающего таймера; Отмена ожидающего таймера;
68. Процедуры завершения ожидания;
1.12. Комплект экзаменационных билетов
Билеты к экзамену по предмету
Билет № 1
1. Классификация программного обеспечения. Системное программное обеспечение.
Понятие операционной среды. Основные принципы построения операционных систем.
2. Использование проецируемых в память файлов. Обработка больших файлов
Билет № 2
1. Объекты ядра Windows.Категории функций API. Защита объектов ядра. Внутреннее устройство объектов ядра
2. Отображение файла в память; Обмен данными между процессами через отображаемый в память файл; Сброс вида в файл
Билет № 3
1. Процессы. Состав процесса. Основные понятия. Описатель экземпляра процесса.
Функция создания процесса CreateProcess, ее параметры. Завершение процесса
2. Использование объекта ядра мьютекс
Билет № 4
Совместное использование объектов ядра несколькими процессами. Дочерние
процессы. Запуск обособленных дочерних процессов
2. . Использование объекта ядра семафор
1.
1
1
1
Билет № 5
1. Базовые сведения о потоках. Создание потока функция CreateThread, ее параметры. Внутреннее устройство потока.
2. Использование объекта ядра событие
Билет № 6
1. Планирование потоков, приоритет и привязка к процессорам.
2. Синхронизация потоков. Синхронизация потоков в пользовательском режиме: использование семейства Interlocked-функций и критических секций
Билет № 7
Приостановка и возобновление потоков. Переключение потоков. Определение периодов выполнения потока. Структура CONTEXT.
2. Проецируемые в память файлы. Проецирование в память EXE- и DLL-файлов
1.
Билет № 8
1. Приоритеты потоков. Абстрагирование приоритетов. Программирование приоритетов. Динамическое изменение уровня приоритета потока.
2. Концепция механизма отображения файлов в память; Создание и открытие объекта, отображающего файл
Билет № 9
1. Синхронизация потоков с использованием объектов ядра:
2. . Управление памятью. Виртуальное адресное пространство процесса.
Билет № 10
1. Разделы адресного пространства. Выделение регионов в адресном пространстве.
Передача региону физической памяти
2. Процедуры завершения ожидания
Билет № 11
1. .Атрибуты защиты страниц физической памяти. Выравнивание данных.
2. Использование объекта ядра ожидаемых таймеров
Билет № 12
1. Исследование виртуальной памяти: использование функций GetSystemInfo(),
GlobalMemoryStatus(), VirtualQuery().
2. Сравнение мьютексов и критических секций
Билет № 13
1
1
2
1. Использование памяти в приложениях. . Использование виртуальной памяти,
2. Асинхронная запись данных
Билет № 14
1. Резервирование региона, передача памяти зарезервированному региону, возврат
физической памяти и освобождение региона.
2. Работа с именованными каналами
Билет № 15
1. . Дополнительные кучи в процессе. Создание и удаление кучи
2. Исключения и их обработчики. Получение кода исключения
Билет № 16
1. Создание DLL модуля. Понятие экспорта и импорта.
2. Оповещение и ожидание события при асинхронном обмене данными
Билет № 17
1. Совместный доступ процессов к данным через механизм проецирования.
2. Работа с почтовыми ящиками в Windows
Билет № 18
1. Статическая и динамическая локальная память потока. Динамическая локальная
память потока
2. Установка асинхронных процедур; Приостановка потока; Ожидание события
Билет № 19
1. Динамически распределяемая память. Стандартная куча процесса
2. .Генерация программных исключений. Необработанные исключения
Билет № 20
1. Распределение и освобождение памяти из кучи. Проверка состояния кучи. Уплотнение кучи
2. Блокирование файлов при асинхронном обмене данными
Билет № 21
1. Изменение размера кучи. Использование куч в программах на С++.
2. Обработка вложенных исключений. Финальная обработка исключений
Билет № 22
1
1
3
1. Динамически подключаемые библиотеки. Преимущества использования библиотек. DLL в адресном пространстве процесса.
2. Встраивание SEN в механизм исключений . С++.
Билет № 23
1. .Явная загрузка DLL и связывание идентификаторов. Явная выгрузка DLL. Явное
подключение экспортируемого идентификатора.
2. Механизм асинхронного вызова процедур
Билет № 24
1.
2.
Отложенная загрузка DLL.
Процедуры завершения ввода-вывода;
Билет № 25
Распределение и освобождение локальной памяти потока; Запись и чтение из локальной памяти потока; Статическая локальная память потока
2. Концепция асинхронного ввода-вывода
1.
Билет № 26
1. Создание и открытие ожидающего таймера; Установка ожидающего таймера; Отмена ожидающего таймера
2. Определение состояния асинхронной операции ввода-вывода
Билет № 27
Файловые системы. Основные понятия и концепции организации ввода/вывода в
ОС. Файловые системы FAT, VFAT, FAT32, NTFS. Особенности использования.
2. Асинхронная запись данных с процедурами завершения
1.
Билет № 28
1. Способы передачи данных между процессами. Передача сообщений. Синхронный
и асинхронный обмен данными. Буферизация
2. Изменение атрибутов защиты виртуальной памяти. Стек потока
Билет № 29
1.
2.
Отмена асинхронной операции ввода-вывода;
Концепция порта завершения; Создание порта завершения; Получение пакета из
порта завершения
Билет № 30
1.
Асинхронное чтение данных с процедурами завершения;
1
1
4
2.
Программирование консольных приложений
1.13. Примерная тематика рефератов
1. Именование временных файлов; создание точки монтирования, установка меток
времени файла;
2. Стратегии обработки файлов: блокирование файлов;
3. Управление системным реестром;
4. Использование обработчиков завершения для повышения качества программ;
5. Управление портами завершения ввода-вывода
1.14. Примерная тематика курсовых работ
1.Создание программного модуля, реализующего использование очередей в многоступенчатом конвейере
2. Реализация программы модели переменных условий
3. Реализация программного модуля, позволяющего настраивать производительность
SMP-систем с помощью спин-счетчиков;
1.15. Примерная тематика квалификационных (дипломных) работ
1. Проектирование безопасной многопоточной DLL для обмена сообщениями через сокет
2. Проектирование приложений, реализующих службы Windows Services
3. Проектироваение масштабируемого сервера, способного обеспечить поддержку большого количества клиентов
1.16. Бально-рейтинговая система
Оценка «отлично» выставляется при условии
–усвоения студентом 95-100% дидактических единиц;
–95-100% правильно выполненных практических и тестовых заданий;
–выполнения расчетно-графического задания и контрольной работы на «хорошо»
или «отлично»
или
– усвоения студентом 90-94% дидактических единиц;
– 90-94% правильно выполненных практических и тестовых заданий;
––выполнения расчетно-графического задания и контрольной работы на «олично»
и написания контрольной работы на «отлично».
Оценка «хорошо» выставляется при условии
– усвоения студентом 80-89% дидактических единиц;
–80-89% правильно выполненных практических и тестовых заданий;
– выполнения расчетно-графического задания и контрольной работы на «хорошо»
написания контрольной работы на «хорошо»
или
1
1
5
– усвоения студентом 70-79% дидактических единиц;
– 70-79% правильно выполненных тестовых заданий;
– –выполнения расчетно-графического задания и контрольной работы на «хорошо»
Оценка «удовлетворительно» выставляется при условии
–усвоения студентом 60-69% дидактических единиц;
–60-69% правильно выполненных практических и тестовых заданий;
–выполнения расчетно-графического задания и контрольной работы на «удовлетворительно »
или
– усвоения студентом 50-59% дидактических единиц;
– 50-59% правильно выполненных тестовых заданий;
– –выполнения расчетно-графического задания и контрольной работы на «удовлетворительно».
1
1
6
Раздел II
Содержательный компонент теоретического материала
Лекция №1. Тема: Классификация программного обеспечения





Типы программного соединения
Назначение операционных систем
Интерфейс программирования Win32 API
Типы данных в Win32 API
Объекты ядра и их дескрипторы в Windows
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 2. Тема: Управление файлами












Накопители на жестких магнитных дисках
Секторы и кластеры, форматирование дисков
Функции файловой системы, файловые системы Windows
Работа с каталогами
Буферизация ввода-вывода и кэширование ввода-вывода
Именование файлов в Windows
Создание и открытие файлов, закрытие и удаление файлов
Запись данных в файл и чтение данных из файла
Копирование, перемещение, замещение файла
Работа с указателем позиции файла
Определение и изменение атрибутов, размеров файла
Блокирование файла
Литература:
1
1
7
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 3 . Тема: Управление потоками и процессами








Определение потока, контекст потока, состояние потока, диспетчеризация и
планирование потоков;
Приостановка и возобновление потоков;
Псевдодескрипторы потоков
Создание и завершение процессов;
Наследование и дублирование дескрипторов
Приоритеты процессов и потоков;
Обслуживание потоков;
Динамическое изменение приоритетов потоков;
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
1
1
8
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4










Лекция №4. Тема: Синхронизация потоков и процессов
Определение синхронизации;
Программная реализация синхронизации;
Примитивы синхронизации;
Критические секции;
Объекты синхронизации и функции ожидания;
Мьютексы;
События;
Семафоры;
Взаимоисключающий доступ к переменным: атомарные операции, замена значения переменной, условная замена значения переменной, инкремент и декремент переменной;
Обнаружение тупиков, восстановление заблокированного процесса, предотвращение тупиков;
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 5. Тема: Программирование консольных приложений






Структура консоли;
Входной буфер консоли, буфер экрана;
Создание консоли, освобождение консоли, стандартные дескрипторы вводавывода;
Работа с окном консоли;
Создание и активизация буфера экрана;
Определение и установка параметров буфера экрана; Ввод-вывод на консоль;
1
1
9
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 6. Тема: Обмен данными между параллельными процессами







Способы передачи данных между процессами;
Передача сообщений;
Синхронный и асинхронный обмен данными;
Буферизация;
Работа с анонимными каналами;
Работа с именованными каналами;
Работа с почтовыми ящиками в Windows;
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
1
2
0
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 7. Тема: Структурная обработка исключений






Исключения и их обработчики;
Получение кода исключения;
Генерация программных исключений;
Необработанные исключения;
Обработка вложенных исключений;
Встраивание SEN в механизм исключений С++; Финальная обработка исключений
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 8. Тема: Работа с виртуальной памятью











Организация виртуальной памяти;
Состояние виртуальной памяти процесса;
Резервирование, распределение и освобождение виртуальной памяти;
Изменение атрибутов доступа к виртуальной странице;
Создание и удаление кучи;
Распределение и освобождение памяти из кучи;
Проверка состояния кучи;
Уплотнение кучи;
Концепция механизма отображения файлов в память;
Создание и открытие объекта, отображающего файл;
Отображение файла в память;
1
2
1


Обмен данными между процессами через отображаемый в память файл;
Сброс вида в файл;
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция №9. Тема: Динамически подключаемые библиотеки
 Концепция динамически подключаемых библиотек;
 Создание DLL;
 Динамическая загрузка и отключение DLL;
 Использование DLL;
 Использование файла определений;
 Статическая загрузка DLL;
 Динамическая локальная память потока;
 Распределение и освобождение локальной памяти потока;
 Запись и чтение из локальной памяти потока;
 Статическая локальная память потока;
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
1
2
2
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 10. Тема: Асинхронная обработка данных










Механизм асинхронного вызова процедур;
Установка асинхронных процедур;
Приостановка потока;
Ожидание события;
Оповещение и ожидание события;
Концепция асинхронного ввода-вывода;
Асинхронная запись данных;
Блокирование файлов;
Определение состояния асинхронной операции ввода-вывода;
Отмена асинхронной операции ввода-вывода;
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
Лекция № 11. Тема: Асинхронная обработка данных
1
2
3
 Процедуры завершения ввода-вывода;
 Асинхронная запись данных с процедурами завершения;
 Асинхронное чтение данных с процедурами завершения;
 Концепция порта завершения;
 Создание порта завершения;
 Получение пакета из порта завершения;
 Создание и открытие ожидающего таймера;
 Установка ожидающего таймера;
 Отмена ожидающего таймера;
 Процедуры завершения ожидания
Литература:
Основная
1. Системное программное обеспечение.А.В. Гордеев, А.Ю.Молчанов.-СПб.:Питер, 2001.736стр ISBN 5-272-00341
2. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с
учетом специфики 64-разрядной версии Windows/ Пер. с англ.-4-е изд.-СПб:Питер;
М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
3. Свен Шрайбер . Недокументированные возможности Windows 2000. Библиотека программиста. –СПб :Питер, 2002.-544стр.:ил. ISBN 5-318-00487-3
4. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы
построения трансляторов./Учебное пособие для высших и средних учебных заведений.СПб.:КОРОНА принт, 2000. -256 с. ISBN 5-7931-0124-1
5.Робачевский А.М. Операционная система UNIX. –СПб.: БХВ-Санкт-Петербург, 2000528 с.:ил.
Дополнительная.
1.Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual C++ 6.00
для профессионалов/Пер. с англ. –СПб:Питер; Издательско-торговый дом «Русская редакция», 2001.—864 стр.:ил. ISBN 5-272-00385-3
2. Солдатов В.П, Программирование драйверов Windows. Изд.2-е, перераб. и доп.-М.:
ООО «Бином-Пресс», 2004 г.- 480 с.: ил. ISBN 5-9518-0099-4
1
2
4
Раздел III
Словарь терминов (глоссарий)
(страницы указаны в соответствии с учебником: Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии
Windows/ Пер. с англ.-4-е изд.-СПб:Питер; М.:Издательско-торговый дом «Русская редакция», 2001.-752 стр.:ил. ISBN 5-272-00384-5
A
ACE 669, 683
ACL 669, 683
AddAccessAllowedAce 945
B
BDC 675
beginthreadex 45
D, E, P, R
DACLb672, 682
endthreadex 47
PDC 673
RID 679
S
SACL 672, 682
SAM 672
SDDL 831
SEN 327
SID 678, 756
SuspendThread 49
А
Администратор системы 662
Адрес:
виртуальный 359
линейный 359
логический 359
физический 359
Адресат 237
Адресация:
ассиметричная 241
косвенная 241
прямая 241
симметричная 241
Адресное пространство процесса 40
Алгоритм:
активног ожидания 104
занимающийся ожиданием 104
Анализ рисков 663
Б
Барьер 131
Блокировка:
спин 103
Буфер 242
ввода-вывода 421
В
Ввод данных:
1
2
5
кэшированных 422
Ввод-вывод:
перекрывающийся 499
Взаимное исключение 97
Входы управления доступом 683
Г
Граф:
распренделения ресурсов 156
Группа:
глобальная 676
локальная 676
первичная 682
специальная 677
учетных записей 676
Д
Действие 95
атомарное 95
неделимое 95
непрерывное 95
условное непрерывное 96
Дескриптор:
безопасности 671б 682
наследуемый 67
ненаследуемый 67
объекта 24
Диск:
жесткий 417
Диспетчер сервиса 609
Домен 673б 674
лес 675
отношения доверия 675
Доступ:
субъектов к объектам 661
к данным 417
З
Задача 40
условной синхронизации 97б 128
Запись:
логическая 420
структура 420
И
Идентификатор:
безопасности 678
действительный 932
ограничивающий 920
Идентификатор учетной записи:
авторизации 678
относительный 679
Имя файла:
длинное 423
Инструкция:
EXPORTS 588
1
2
6
LIBRARY 588
непрерывная 95
Исключение 327
обработчик 327
К
Канал:
анонимный 243
именованный 265
передачи данных 237
Каталог 420
таблиц страниц 363
текущий 477
Клиент:
анонимного канала 243
именованного канала 263
почтового ящика 307
Когерентность данных 561
Код:
охраняемый 327
последней ошибки 53
Команжа:
непрерывная 95
Консоль 167
буфер экрана 167
входной буфер 167
Контекст:
действия 95
потока 31
потока в Windows 41
процесса 40
безопасности субъекта 687
Контроль доступа 661
Критическая секция 97
Куча 393
сериализуемая 303
М
Магнитный диск:
дорожка 417
зона 410
разбиение на разделы 419
раздел 419
сектор 418
форматирование высокого уровня 419
форматирование низкого уровня 419
цилиндр 417
Макрокоманда
_endthreadex 47
Маркер:
ограниченного доступа 920
Маркер доступа 671
дублирование 927
замещение 692, 929
1
2
7
Матрица управления доступами 665
Менеджер:
потоков 38
безопасности 662
Многозадачность вытесняющая 82
Модель:
безопасности 663
управления 667
Монитор безопасности 662
Мьютекс 121
забытый 117
Н
НЖМД 417
Нить 29
О
Обмен данными:
между параллельными процессами 237
Обмен сообщениями:
асинхронный 242
синхронный 242
Обработка исключений финальная 351
Обслуживание потоков:
FCFS 38
FIFO 38
циклическое 38
Объект 661
наследуемый 67
ненаследуемый 67
охраняемый в Windows 671
синхронизации 115
Ожидание:
активное 103
Операционная система 19
многопользовательская 20
мультипрограммная 20
мультипроцессорная 20
однопользовательская 20
однопрограммная 20
однопроцессорная 20
реального времени 20
Откат 159
Отображение файла 561
Отправитель 237
сообщения 241б 242
П
Память:
виртуальная 359
виртуальная страничная 360
кэш 421
реальная 360
физическая 359
потока (динамическая локальная) 594
1
2
8
потока (статическая локальная) 603
процесса логическая 359
Передача данных:
потоком 239
сообщениями 239
Политика безопасности 662
дискреционная 664
либеральная дискреционная 664
механизм реализации 662
строгая дискреционная 663
Получатель 237
сообщения 242
Пользовательские программы 19
Порт:
завершения ввода-вывода 536
ключ завершения 536
Поток 29
безопасное завершение работы 162
в Windows 41
главный 42
интерфейса пользователя 42
контрольная точка 159
параллельные 30
первичный 42
пользовательский 41
потребитель 108
рабочий 42
системный 41
управления 29
Почтовый ящик 307
Права доступа:
специфические 684
стандартные 684
эффективные 875
Правила управления доступом 663
Право 662
Привилегия 662, 687
Приложение 20
консольное 167
Примитив синхронизации 104
семафор 107
условие 105
Приоритет потока:
базовый 85
основной 85
уровень 86
Программа:
многопоточная 30
однопоточная 30
реетерабельная 33
Протокол 241
Профиль пользователя 669
1
2
9
Процедура:
асинхронная 485
завершения ввода-вывода 528
Процесс 40
в Windows 58
восстановление 158
дочерний 59
рабочее множество страниц 363
реального времени 83
родительский 59
с высоким приоритетом 83
с нормальным приоритетом 83
фоновый 83
Псевдодескриптор
потока 52
процесса 81
текущего процесса 81
Пул памяти 393
Р
Разрешения 684
Рандеву 242
Раскрутка стека
глобальная 344
Режим:
доступа к объекту 666
управления объектом 666
Ресурс:
контроль доступа 661
монопольный 154
неперераспределяемый 155
объекты 661
перераспределяемый 155
повторно используемый 155
потребляемый 155
разделяемый 98
совместно используемый 98, 154
субъекты 661
компьютера 19
Ресурсы:
аппаратные 19
информационные 19
логические 19
системные 19
физические 19
Риск:
анализ 663
управления 663
С
Связь:
дуплексная 239
полудуплексная 239
Сегмент:
1
3
0
виртуальной памяти 362
Семафор:
бинарный 108
сильный 108
слабый 108
считывающий 108
Сервер:
анонимного канала 243
именованного канала 265
почтового ящика 307
Сервис 607
Синхронизация:
потоков 96
процессов 96
условная 97
Системные ресурсы 19
Событие 97, 128
Сообщение 239
Состояние:
безопасное 663
настороженное состояние потока 486
несигнальное 115
подвешенное состояние потока 36
потока 34
поток блокировки 34
поток готов 34
поток исполняется 34
поток спит 36
приостановленное состояние потока 36
программы 34
процессора 34
сигнальное 115
системы безопасности 663
Список:
управления дискреционным доступом 672
управления доступом 669, 672
Стандартный ввод-вывод
перенаправление 258
Страница:
виртуальной памяти 360
Структура 420
Субъект 661
возможности 669
Т
Таймер:
ожидающий 544
ожидающий непериодический 545
ожидающий периодический 545
синхронизации 544
Топология связи 239
Транзакция 159
Тупик 153
1
3
1
У
Узел:
графа 158
Управление:
рисками 663
файлами 420
Учетная запись:
администратора 674
гостя 674
домена 673
компьютера 673
системы 674
Ф
Файл 420
вид 561
подкачки 360
представление 561
путь 423
страниц 360
указатель 420
Фрейм 327
стека 344
Функции:
_controlfp 342
_set_se_translator 348
AbnormalTermination 353
AddAccessAllowedAceEx 952
AddAccessDeniedAce 946
AddAccessDeniedAceEx 953
AddAce 971
AddAuditAccessAce 960
AddAuditAccessAceEx 970
AdjustTokenGroups 918
AdjustTokenPrivileges 917
AllocateAndInitializeSid 761
AllocateLocallyUniqueId 887
AllocConsole 172
BuildExplicitAccessWithName 849
BuildTrusteeWithName 842
BuildTrusteeWithSid 844
CallNamedPipe 293
CancelIO 522
CancelWaitableTimer 549
ChangeServiceConfig 637
CharToOem 55
CheckTokenMembership 932
ConnectNamedPipe 268
ControlService
ConvertSecurityDescriptorToString
SecurityDescriptor 835
ConvertSidToStringSid 782
CopyFile 435
1
3
2
CopyFileEx 437
CopyMemory 383
CopySid 777
CreateConsole ScreenBuffer 188
CreateDirectory 468
CreateDirectoryEx 469
CreateFile 270, 424
CreateFileMapping 563
CreateIoCompletionPort 537
CreateMailslot 308
CreateNamedPipe 266
CreatePipe 244
CreateProcess 58
CreateRest rictedToken 921
CreateService 621
CreateThread 42
CreateWaitableTimer 545, 546
DeleteAce 977
DeleteFile 427
DeleteService 649
DisconnectNamedPipe 268
DllMain 579
DuplicateHandle 75
DuplicateToken 927
EqualPrefixSid 778
EqualSid 778
ExitProcess 64
ExitThread 47
FileTimeToSystemTime 461
FillConsoleOutputAttribute 197
FillConsoleOutputCharacter 219
FillMemory 383
FindClose 472
FindFirstChangeNotification 480
FindFirstFreeAce 986
FreeConsole 177
FreeLibrary 583
FreeSid 762
GetAce 972
GetConsoleMode 226
GetConsoleTitle 181
GetConsoleWindow 180
GetCurrentDirectory 477
GetCurrentProcess 81
GetCurrentThread 52
GetFileAttributes 446
GetFileSecurity 1008
GetFleSize 449
GetFileType 464
GetHandleInformation 74
GetLastError 53
GetNamedPipeInfo 303
1
3
3
GetOverlappedResult 518
GetProcessHeap 393
GetSecurityInfo 806
GetServiceKeyName 641
GetStdHandle 178
HeapAlloc 395
HeapCompact 411
HeapCreate 394
HeapDestroy 394
HeapFree 395
HeapLock 403
HeapReAlloc 401
HeapUnlock 403
HeapValidatec406
HeapWalk 410
InterlockedCompareExchange 146
InterlockedDecrement 148
InterlockedExchange 144
InterlockedIncrement 148
LoadLibrary 582
LoadLibraryEx 582
LockFile 455
LockFileEx 511
lockServiceDatabase 653
MapViewOfFile 564
MoveFile 437, 476
MoveMemory 384
OpenProcessToken 894
OpenSCManager 620
OpenService 627
PeekNamedPipe 285
PostQueuedCompletionStatus 539
QueryServiceConfig 634
QueueUserAPC 486
RaiseException 337
ReadConsole 203
ReadFile 433, 506
ReadFileEx 532
ReadProcessMemory 388
ReplaceFile 438
ResumeThread 49
SetConsoleMode 225
SetConsoleTitle 182
SetCurrentDirectory 478
Sleep 50
StartService 627
TlsAlloc 595
TlsFree 595
TlsGetValue 595
TransactNamedPipe 289
UnlockFile 456
VirtualAlloc 368
1
3
4
WriteFile 246, 247, 428. 500
ZeroMemory 61, 383
безопасная для потоков 32, 33
блокирующие 143
импортируемая 584
ожидания 116
обратного вызова 43
повторно входимая 32
Я
Язык системного программирования 104
1
3
5
Раздел IV
Практикум по решению заданий
Управление файлами
#include <windows.h>
#include <iostream.h>
int main()
{
HANDLE hFile;
// создаем файл для записи данных
hFile = CreateFile(
"C:\\demo_file.dat",
// имя файла
GENERIC_WRITE,
// запись в файл
0,
// монопольный доступ к файлу
NULL,
// защиты нет
CREATE_NEW,
// создаем новый файл
FILE_ATTRIBUTE_NORMAL, // обычный файл
NULL
// шаблона нет
);
// проверяем на успешное создание
if (hFile == INVALID_HANDLE_VALUE)
{
cerr << "Create file failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to finish.";
cin.get();
return 0;
}
// пишем данные в файл
for (int i = 0; i < 10; ++i)
{
DWORD dwBytesWrite;
if (!WriteFile(
hFile,
// дескриптор файла
&i,
// адрес буфера, откуда идет запись
sizeof(i),
// количество записываемых байтов
&dwBytesWrite,
// количество записанных байтов
(LPOVERLAPPED)NULL
// запись синхронная
))
{
cerr << "Write file failed." << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hFile);
cout << "Press any key to finish.";
cin.get();
return 0;
}
}
// закрываем дескриптор файла
CloseHandle(hFile);
cout << "The file is created and written." << endl;
return 0;
}
Управление потоками и процессами
#include <windows.h>
#include <conio.h>
1
3
6
volatile int count;
void thread()
{
for (;;)
{
count++;
Sleep(500);
_cprintf ("count = %d\n", count);
}
}
int main()
{
// имя нового процесса с пробелом
char lpszComLine[80]="C:\\ConsoleProcess.exe ";
// для символьного представления дескриптора
char lpszHandle[20];
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE hThread;
DWORD IDThread;
_cputs("Press any key to start the count-thread.\n");
_cputs("After terminating the thread press any key to exit.\n");
_getch();
// запускаем поток-счетчик
hThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)thread, NULL,
0, &IDThread);
if (hThread == NULL)
return GetLastError();
// делаем дескриптор потока наследуемым
if(!SetHandleInformation(
hThread,
// дескриптор потока
HANDLE_FLAG_INHERIT,
// изменяем наследование
дескриптора
HANDLE_FLAG_INHERIT)) // делаем дескриптор наследуемым
{
_cputs("The inheritance is not changed.\n");
_cputs("Press any char to finish.\n");
_getch();
return GetLastError();
}
// устанавливаем атрибуты нового процесса
ZeroMemory(&si, sizeof(STARTUPINFO));
1
3
7
si.cb=sizeof(STARTUPINFO);
// преобразуем дескриптор в символьную строку
_itoa((int)hThread,lpszHandle,10);
// создаем командную строку
strcat(lpszComLine,lpszHandle);
// запускаем новый консольный процесс
if (!CreateProcess(
NULL,
// имя процесса
lpszComLine, // адрес командной строки
NULL,
// атрибуты защиты процесса по умолчанию
NULL,
// атрибуты защиты первичного потока по умолчанию
TRUE,
// наследуемые дескрипторы текущего процесса
// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL,
// используем среду окружения процесса предка
NULL,
// текущий диск и каталог, как и в процессе
предке
&si,
// вид главного окна - по умолчанию
&pi
// здесь будут дескрипторы и идентификаторы
// нового процесса и его первичного потока
)
)
{
_cputs("The new process is not created.\n");
_cputs("Press any key to finish.\n");
_getch();
return GetLastError();
}
// закрываем дескрипторы нового процесса
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
_getch();
// закрываем дескриптор потока
CloseHandle(hThread);
return 0;
}
Синхронизация потоков и процессов
#include <windows.h>
#include <iostream.h>
int main()
{
HANDLE hMutex;
char lpszAppName[] = "C:\\ConsoleProcess.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
// создаем мьютекс
hMutex = CreateMutex(NULL, FALSE, "DemoMutex");
1
3
8
if (hMutex == NULL)
{
cout << "Create mutex failed." << endl;
cout << "Press any key to exit." << endl;
cin.get();
return GetLastError();
}
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// создаем новый консольный процесс
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
NULL, NULL, NULL, &si, &pi))
{
cout << "The new process is not created." << endl;
cout << "Press any key to exit." << endl;
cin.get();
return GetLastError();
}
// выводим на экран строки
for (int j = 0; j < 10; ++j)
{
// захватываем мьютекс
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < 10; i++)
{
cout << j << ' ' << flush;
Sleep(10);
}
cout << endl;
// освобождаем мьютекс
ReleaseMutex(hMutex);
}
// закрываем дескриптор мьютекса
CloseHandle(hMutex);
// ждем пока дочерний процесс закончит работу
WaitForSingleObject(pi.hProcess, INFINITE);
// закрываем дескрипторы дочернего процесса в текущем процессе
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
Программирование консольных приложений
#include <windows.h>
1
3
9
#include <iostream.h>
int main()
{
char lpszAppName[] = "C:\\ConsoleProcess.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
// заполняем поля структуры STARTUPINFO
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpTitle = "This is a new title";
si.dwX = 200;
// позиция левого угла окна консоли
si.dwY = 200;
si.dwXSize = 200;
// размеры окна
si.dwYSize = 100;
si.dwXCountChars = 150; // размер буфера экрана по
горизонтали
si.dwYCountChars = 50;
// размер буфера экрана по вертикали
// красные буквы на синем фоне
si.dwFillAttribute = FOREGROUND_RED|FOREGROUND_INTENSITY|
BACKGROUND_BLUE|BACKGROUND_INTENSITY;
// используем все параметры, что установили
si.dwFlags = STARTF_USECOUNTCHARS|STARTF_USEFILLATTRIBUTE|
STARTF_USEPOSITION|STARTF_USESIZE;
si.wShowWindow = SW_SHOWNORMAL;
// запускаем процесс, который сам распределяет консоль
if (!CreateProcess(lpszAppName, NULL, NULL, NULL, FALSE,
DETACHED_PROCESS, NULL, NULL, &si, &pi))
{
cout << "The new process is not created." << endl
<< "Check a name of the process." << endl
<< "Press any key to finish." << endl;
cin.get();
return 0;
}
// закрываем дескрипторы процесса
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
Обмен данными между параллельными процессами
#include <windows.h>
#include <iostream.h>
#include <string.h>
int main()
{
char
machineName[80];
1
4
0
char
HANDLE
DWORD
тов
char
char
int
pipeName[80];
hNamedPipe;
dwBytesRead;
// для количества прочитанных бай-
pchInBuffer[80];
pchOutBuffer[80];
nMessageLength;
// для записи сообщения
// для чтения сообщения
// длина сообщения
// вводим имя машины в сети, на которой работает сервер
cout << "Enter a name of the server machine: ";
cin >> machineName;
// подставляем имя машины в имя канала
wsprintf(pipeName, "\\\\%s\\pipe\\demo_pipe", machineName);
// связываемся с именованным каналом
hNamedPipe = CreateFile(
pipeName,
// имя канала
GENERIC_READ | GENERIC_WRITE,
// читаем и записываем в
канал
FILE_SHARE_READ | FILE_SHARE_WRITE, // разрешаем чтение и
запись
NULL,
// безопасность по умолчанию
OPEN_EXISTING,
// открываем существующий канал
FILE_ATTRIBUTE_NORMAL,
// атрибуты по умолчанию
NULL);
// дополнительных атрибутов нет
// проверяем связь с каналом
if (hNamedPipe==INVALID_HANDLE_VALUE)
{
cerr << "Connection with the named pipe failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to exit.";
cin.get();
return 0;
}
// вводим строку
cin.get();
cout << "Input a string: ";
cin.getline(pchInBuffer, 80);
// определяем длину строки
nMessageLength = strlen(pchInBuffer) + 1;
// пишем и читаем из именованного канала одной транзакцией
if (!TransactNamedPipe(
hNamedPipe,
// дескриптор канала
&pchInBuffer,
// адрес входного буфера канала
nMessageLength, // длина входного сообщения
&pchOutBuffer,
// адрес выходного буфера канала
sizeof(pchOutBuffer),
// длина выходного буфера канала
&dwBytesRead,
// количество прочитанных байтов
NULL))
// передача транзакции синхронная
1
4
1
{
// ошибка транзакции
cerr << "Transact named pipe failed: " << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hNamedPipe);
cout << "Press any key to exit.";
cin.get();
return 0;
}
// выводим посланное сообщение на консоль
cout << "The sent message: "
<< endl << '\t' << pchInBuffer << endl;
// выводим полученное сообщение на консоль
cout << "The received message: "
<< endl << '\t' << pchOutBuffer << endl;
// закрываем дескриптор канала
CloseHandle(hNamedPipe);
// завершаем процесс
cout << "Press any key to exit.";
cin.get();
return 0;
}
Структурная обработка исключений
#include <windows.h>
#include <iostream.h>
int main()
{
int *p = NULL;
// пустой указатель на целое число
__try
{
if (!p)
{
cout << "Exit with __leave from the try block." << endl;
__leave;
}
else
{
*p = 10;
// выходим их блока
cout << "*p = " << *p << endl;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
cout << "There was some exception." << endl;
}
1
4
2
return 0;
}
Работа с виртуальной памятью
#include <windows.h>
#include <iostream.h>
int main()
{
HANDLE hHeap;
int *a = NULL;
int h_size = 4096;
int a_size = 2048;
// указатель на массив
// размер кучи
// размер массива
// создаем кучу динамически
hHeap = HeapCreate(HEAP_NO_SERIALIZE, h_size, h_size);
if (!hHeap)
{
cout << "Heap create failed." << endl;
return GetLastError();
}
// распределям память под массив
a = (int*)HeapAlloc(hHeap, NULL, a_size);
// обрабатываем ошибку в случае неудачи
if (!a)
{
cout << "Heap allocation failed." << endl;
return GetLastError();
}
// распечатываем распределённую память
cout << "a[10] = " << a[10] << endl;
// освобождаем память из кучи
if (!HeapFree(hHeap, NULL, a))
{
cout << "Heap free failed." << endl;
return GetLastError();
}
// разрушаем кучу
if (!HeapDestroy(hHeap))
{
cout << "Heap destroy failed." << endl;
return GetLastError();
}
return 0;
}
Динамически подключаемые библиотеки
#include <windows.h>
// главная функция
1
4
3
BOOL WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
// загрузка DLL
break;
case DLL_THREAD_ATTACH:
// создание потока
break;
case DLL_THREAD_DETACH:
// завершение потока
break;
case DLL_PROCESS_DETACH:
// отключение DLL
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) int count = 0;
extern "C" __declspec(dllexport) int Add(int n)
{
count += n;
return count;
}
extern "C" __declspec(dllexport) int Sub(int n)
{
count -= n;
return count;
}
#include <windows.h>
#include <iostream.h>
int main()
{
HMODULE hDll;
int (*Add)(int);
int (*Sub)(int);
int *pCount;
//
//
//
//
дескриптор
для адреса
для адреса
для адреса
DLL
функции Add из DLL
функции Sub из DLL
переменной count из DLL
// загружаем динамически подключаемую библиотеку
hDll = LoadLibrary("Count.dll");
if (!hDll)
{
cerr << "Load library failed." << endl;
return GetLastError();
}
// настраиваем адрес переменной count из DLL
pCount = (int *)GetProcAddress(hDll, "count");
if (!pCount)
1
4
4
{
cerr << "Get variable address failed." << endl;
return GetLastError();
}
// выводим начальное значение переменной count
cout << "Initial count = " << (*pCount) << endl;
// настраиваем адреса функций
Add = (int (*)(int))GetProcAddress(hDll, "Add");
Sub = (int (*)(int))GetProcAddress(hDll, "Sub");
if (!Add || !Sub)
{
cerr << "Get procedure address failed." << endl;
return GetLastError();
}
// изменяем значение счетчика
cout << "count = " << Add(20) << endl;
cout << "count = " << Sub(15) << endl;
// отключаем библиотеку
if (!FreeLibrary(hDll))
{
cerr << "Free library failed." << endl;
return GetLastError();
}
// выходим из программы
cout << "Press any key to exit.";
cin.get();
return 0;
}
Асинхронная обработка данных
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <iostream.h>
int main()
{
HANDLE hFile;
HANDLE hEndWrite;
OVERLAPPED ovl;
ступом к файлу
// дескриптор файла
// дескриптор события
// структура управления асинхронным до-
// создаем события с автоматическим сбросом
hEndWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEndWrite == NULL)
return GetLastError();
// инициализируем структуру OVERLAPPED
ovl.Offset = 0;
// младшая часть смещения равна 0
ovl.OffsetHigh = 0;
// старшая часть смещения равна 0
ovl.hEvent = hEndWrite; // событие для оповещения завершения
записи
1
4
5
// создаем файл для записи данных
hFile = CreateFile(
"C:\\demo_file.dat",
// имя файла
GENERIC_WRITE,
// запись в файл
FILE_SHARE_WRITE,
// совместный доступ к файлу
NULL,
// защиты нет
OPEN_ALWAYS,
// открываем или создаем новый файл
FILE_FLAG_OVERLAPPED, // асинхронный доступ к файлу
NULL
// шаблона нет
);
// проверяем на успешное создание
if (hFile == INVALID_HANDLE_VALUE)
{
cerr << "Create file failed." << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hEndWrite);
cout << "Press any key to finish.";
cin.get();
return 0;
}
// пишем
for (int
{
DWORD
DWORD
DWORD
данные в файл
i = 0; i < 10; ++i)
dwBytesWrite;
dwNumberOfBytesTransferred;
dwRet;
if (!WriteFile(
hFile,
// дескриптор файла
&i,
// адрес буфера, откуда идет запись
sizeof(i),
// количество записываемых байтов
&dwBytesWrite, // количество записанных байтов
&ovl
// запись асинхронная
))
{
dwRet = GetLastError();
if (dwRet == ERROR_IO_PENDING)
cout << "Write file pending." << endl;
else
{
cout << "Write file failed." << endl
<< "The last error code: " << dwRet << endl;
return 0;
}
}
// проверяем состояние асинхронной операции записи
1
4
6
if (!GetOverlappedResult(
hFile,
// дескриптор файла
&ovl,
// адрес структуры для асинхронной работы
&dwNumberOfBytesTransferred, // количество переданных
байтов
FALSE
// не ждать завершения операции записи
))
{
cout << "Get overlapped result failed." << endl
<< "The last error code: " << GetLastError() << endl;
return 0;
}
else
cout << "Number of bytes transferred: "
<< dwNumberOfBytesTransferred << endl;
// ждем завершения асинхронной операции записи
WaitForSingleObject(hEndWrite, INFINITE);
// увеличивает смещение в файле
ovl.Offset += sizeof(i);
}
// закрываем дескрипторы
CloseHandle(hFile);
CloseHandle(hEndWrite);
cout << "The file is written." << endl;
return 0;
}
1
4
7
Раздел V
Изменения в рабочей программе,
которые произошли после утверждения программы
Характер изменений в
программе
Номер и дата протокола заседания кафедры, на котором
было принято данное решение
Подпись заведующего
кафедрой, утверждающего внесенное изменение
Подпись декана факультета (проректора по учебной
работе), утверждающего
данное изменение
1
4
8
Раздел VI
Учебные занятия по дисциплине ведут:
Ф.И.О., ученое звание и
степень преподавателя
Яковлева Л.В.,
ст. преподаватель
Учебный
год
Факультет
Специальность
2010-2011
ФМОИП
Прикладная математика и информатика
1
4
9
Download