- •Введение
- •1. Лабораторная работа № 1
- •1.1. Цель работы
- •1.2. Теоретическое введение
- •1.2.1. Получение информации об операционной системе
- •1.2.2. Получение информации из реестра
- •1.2.3. Получение информации о системных каталогах Windows
- •1.2.4. Получение информации о диске
- •1.3. Создание приложения для получения характеристик компьютера и операционной системы
- •Контрольные вопросы
- •2. Лабораторная работа №2
- •2.1.Цель работы
- •2.2. Теоретическое введение
- •2.2.1. Процедуры и функции для работы с виртуальной памятью
- •2.3. Создание приложения, работающего с виртуальной памятью
- •2.4. Задание для самостоятельной работы
- •Контрольные вопросы
- •3. Лабораторная работа № 3
- •3.1. Цель работы
- •3.2. Пример использования механизма выделения виртуальной памяти для решения конкретных задач
- •3.3. Задания для самостоятельной работы
- •Контрольные вопросы
- •4. Лабораторная работа № 4
- •4.1. Цель работы
- •4. 2. Теоретическое введение
- •4.2.1 Создание или открытие объекта ядра «файла»
- •4.2.2 Создание объекта ядра «файл, проецируемый в память»
- •4.2.3 Проецирование файловых данных на адресное пространство процесса
- •4.2.4 Отмена проецирования на адресное пространство процесса объекта ядра «файл, проецируемый в память»
- •4.2.5 Закрытие объектов ядра «файл, проецируемый в память» и «файл»
- •4.3 Примеры программ, выполняющих проецирование в память
- •4.3.1 Пример 1
- •4.3.2 Пример 2
- •4.4. Задания для самостоятельной работы
- •Контрольные вопросы
- •5. Лабораторная работа № 5
- •5.1.Цель работы
- •5.2. Теоретическое введение
- •5.2.1. Создание процесса
- •5.2.2. Запуск внешней программы функцией WinExec
- •5.2.3. Запуск внешней программы и открытие документа функцией ShellExecute
- •При успешном выполнении функция ShellExecute возвращает целое значение, большее 32. Значение меньшее или равное 32 указывает на ошибку. Значения эти те же, что и для функции WinExec.
- •5.2.4. Создание потока
- •5.2.5. Завершение процесса
- •5.2.6. Завершение потока
- •5.2.7. Изменение класса приоритета процесса
- •5.2.8. Получение информации о классе приоритета процесса
- •5.2.9. Изменение уровня приоритета потока
- •5.2.10. Получение информации о приоритете потока
- •5.3. Примеры программ для работы с процессами и потоками
- •5.3.1. Создание процесса с помощью функции CreateProcess.
- •5.3.2. Создание процесса с помощью функции WinExec.
- •5.3.3. Создание процесса с помощью функции ShellExecute.
- •5.3.4. Создание многопоточного приложения.
- •5.4. Задания для самостоятельной работы
- •Контрольные вопросы
- •6. Лабораторная работа № 6
- •6.1. Цель работы
- •6.2. Теоретическое введение
- •6.2.1. Получение «мгновенного снимка» системы
- •6.2.2. Получение информации о процессах
- •6.2.3. Получение информации о потоках
- •6.2.4. Получение информации о модулях
- •6.2.5. Информация о кучах (heap)
- •6.2.6. Информация о виртуальной памяти.
- •6.2.7. Алгоритм работы функций ToolHelp
- •6.2.8. Как получить карту памяти любого процесса
- •6.3. Пример использования функций ToolHelp
- •6.4. Задания для самостоятельной работы
- •Контрольные вопросы
- •7. Лабораторная работа № 7
- •7.1. Цель работы
- •7.2. Теоретическое введение
- •7.2.1. Критические секции
- •7.2.2. Синхронизация с использованием объектов ядра
- •7.2.3. Wait-функции
- •7.2.4. Синхронизация с использованием процессов и потоков
- •7.2.5. Объекты Mutex
- •7.2.6. Семафоры
- •7.2.7. События
- •7.3 Примеры работы с объектами синхронизации
- •7.3.1 Пример 1
- •7.3.1 Пример 2
- •7.4. Задания для самостоятельной работы
- •Контрольные вопросы
- •8. Лабораторная работа № 8
- •8.1. Цель работы
- •8.2 Теоретическое введение
- •8.2.1 Создание dll
- •8.2.2 Неявная загрузка dll
- •8.2.3 Явная загрузка dll
- •8.2.4 Внедрение dll в адресное пространство другого процесса
- •8.3 Пример работы с dll
- •8.3.1 Создание dll, которая выполняет перехват нажатых клавиш
- •8.3.2 Разработка приложения, которое выполняет анализ и обработку нажатых клавиш.
- •8.4 Индивидуальные задания
- •Контрольные вопросы
- •9.2.2. Функции для работы с объектом «уведомление об изменении файловой системы»
- •9.3. Пример работы системы уведомления об изменениях в файловой системе
- •9.4. Задания для самостоятельной работы
- •Контрольные вопросы
- •Литература
- •214013 Г. Смоленск, Энергетический проезд, 1
7.2.4. Синхронизация с использованием процессов и потоков
Процессы и потоки можно использовать и для решения задач синхронизации.
Объект ядра «процесс» сразу после создания всегда находятся в занятом состоянии. В момент завершения процесса операционная система автоматически освобождает его объект ядра «процесс», и он навсегда остается в свободном состоянии.
Точно такие же правила распространяются и на объекты ядра «поток». Они тоже сразу после создания находятся в занятом состоянии. Когда поток завершается, операционная система автоматически переводит объект ядра «поток» в свободное состояние. Как и объект ядра «процесс», объект ядра «поток» никогда не возвращается в занятое состояние.
7.2.5. Объекты Mutex
Объекты ядра Mutex (мьютекс) гарантируют потокам взаимоисключающий доступ к единственному ресурсу. Мьютексы ведут себя точно так же, как и критические секции. Однако, если последние являются объектами пользовательского режима, то мьютексы — объекты ядра. Кроме того, объект Mutex позволяет синхронизировать доступ к ресурсу нескольких потоков из разных процессов; при этом можно задать максимальное время ожидания доступа к ресурсу.
Для использования объекта Mutex один из процессов должен сначала создать его вызовом CreateMutex:
function CreateMutex(lpMutexAttributes: PSecurityAttributes;
bInitialOwner: Boolean; lpName: PChar): THandle;
где lpMutexAttributes – указывает на структуру SECURITY_ATTRIBUTES, которая содержит информацию о защите объекта ядра «mutex». Если защиты не нужно в этот параметр заносится nil.
bInitialOwner – определяет начальное состояние мьютекса. Если в нем передается FALSE (что обычно и бывает), объект-мьютекс не принадлежит ни одному из потоков и поэтому находится в свободном состоянии. Если же в нем передается TRUE, мьютекс изначально находится в занятом состоянии.
lpName – указатель на сроку, , заканчивающуюся двоичным нулем и содержащую имя объекта «mutex». Применяется в тех случаях, когда объект «mutex» используется для синхронизации потоков разных процессов. Если мьютекс используется для синхронизации потоков одного процесса, этот параметр устанавливается в nil.
При успешном выполнении функция CreateMutex возвращает дескриптор мьютекса, В случае ошибки функция возвращает nil. Причем, если при вызове функции CreateMutex указывается имя мьютекса и объект мьютекс с таким именем уже существует, то функция вернет значение – nil, а функция GetLastError вернет значение - ERROR_ALREADY_EXISTS.
Любой процесс может получить свой («процессно-зависимый») дескриптор существующего объекта "мьютекс", вызвав функцию OpenMutex:
function OpenMutex(dwDesiredAccess: DWORD; bInheritHandle: Boolean;
lpName: PChar): THandle;
где dwDesiredAccess - определяет требуемый доступ к мьютексу. Возможные значения данного параметра приведены в таблице 7.1.
bInheritHandle - определяет тип наследования дескриптора. Если данный параметр имеет значение TRUE, процесс, создаваемый функцией CreateProcess, будет наследовать данный дескриптор. Если же параметр имеет значение FALSE, дескриптор мьютекса не будет наследуемым.
lpName - указатель на сроку, заканчивающуюся двоичным нулем и содержащую имя мьютекса.
Таблица 7.1 Значения параметра dwDesiredAccess
Значение |
Описание |
MUTEX_ALL_ACCESS |
Означает все возможные флаги доступа для мьютекса |
SYNCHRONIZE |
Допускается использование дескриптора объекта мьютекс в любой wait- функции для ожидания освобождения мьютекса |
Поток получает доступ к разделяемому ресурсу, вызывая одну из Wait-функций и передавая ей дескриптор мьютекса, который охраняет этот ресурс. Wait-функция проверяет состояние мьютекса. Если объект мьютекс свободен, Wait-функция переводит мьютекс в занятое состояние и разрешает продолжение выполнения потока.
Если Wait-функция определяет, что мьютекс занят, то поток переходит в состояние ожидания освобождения объекта мьютекс.
Когда ожидание мьютекса потоком успешно завершается, последний получает монопольный доступ к защищенному ресурсу. Все остальные потоки, пытающиеся обратиться к этому ресурсу, переходят в состояние ожидания. Когда поток, занимающий ресурс, заканчивает с ним работать, он должен освободить мьютекс вызовом функции ReleaseMutex
function ReleaseMutex(hMutex: THandle): Boolean;
где hMutex – дескриптор объекта мьютекс.
При успешном выполнении функция ReleaseMutex возвращает значение TRUE.
Объект мьютекс отличается от остальных объектов ядра тем, что занявшему его потоку передаются права на владение им. Объекты мьютексы способны запоминать, какому потоку они принадлежат. Если какой-то посторонний поток попытается освободить мьютекс вызовом функции ReleaseMutex, то данная функция вернет FALSE. Вызов функции GetLastError даст значение ERROR_NOT_OWNER.