
- •1.1 Основы программирования в операционной системе Windows
- •1.1.1 Вызов функций api
- •1.1.2 Структура программы
- •1.2 Вопросы системного программирования в Windows
- •1.2.1 Страничная и сегментная адресация.
- •1.2.2 Адресное пространство процесса.
- •2.1 Управление процессами
- •2.2 Процессы и потоки в Windows
- •2.3 Создание процессов
- •2.4 Определение исполняемого образа и командной строки
- •2.5 Идентификация процессов
- •3.1 Создание потока. Функция CreateThread
- •3.2. Завершение потока
- •3.3 Другие функции работы с потоками
- •3.4 Структура context
- •3.5 Приоритеты потоков
- •4.1 Объект critical_section
- •4.2 Мьютексы
- •4.3 Семафоры
- •5.1 События
- •7.1 Кучи
- •7.2 Управление памятью кучи
- •Другие функции для работы с кучей
- •Резюме по управлению кучей
- •Отображение адресного пространства процесса в объекты отображения
- •Что такое импорт
- •Явная загрузка dll
- •Явное подключение экспортируемого идентификатора
- •10.1 Управление файлами и каталогами Создание и открытие файлов
- •10.2 Управление каталогами
- •10.3 Другие методы получения атрибутов файлов и каталогов
- •11.1 Блокировка файлов
- •11.2 Реестр
- •12.1 Стандартные устройства и консольный ввод-вывод
- •12.2 Асинхронный ввод-вывод и порты завершения
- •Параметры
- •Цели системы безопасности
- •Параметры
- •Аварийное завершение
- •Использование именованных каналов
- •Параметры
- •Наблюдение за сообщениями в именованном канале
- •Параметры
5.1 События
Последний объект ядра для синхронизации — события. Этот объект используется для информирования других потоков о том, что произошло некоторое событие, например стало доступно новое сообщение.
Важная дополнительная возможность, предоставляемая событиями, — освобождение нескольких потоков от совместного ожидания, когда в сигнальное состояние перешел один дескриптор. События делятся на сбрасываемые автоматически и вручную, это свойство события устанавливается при вызове функции CreateEvent.
- Событие, сбрасываемое вручную, может сигнализировать одновременно не скольким потокам, выполняющим ожидание события.
- События с автоматическим сбросом посылают сигналы единственному потоку, выполняющему ожидание события, и сбрасываются автоматически.
Событиями используются функции CreateEvent, OpenEvent, SetEvent, ResetEvent и PulseEvent.
HANDLE CreateEvent ( LPSECURITY_ATTRIBUTES lpsa,
BOOL fManualReset, BOOL fInitialState, LPCTSTR lpszEventName)
При установленном в значение TRUE параметре fManualReset создается событие с ручным сбросом. Аналогично, если событие первоначально должно находиться в сигнальном состоянии, параметр fInitialState необходимо установить в значение TRUE. Чтобы открыть существующее событие, возможно, из другого процесса, следует воспользоваться функцией OpenEvent.
Для управления событиями используются следующие три функции:
BOOL SetEvent (HANDLE hEvent)
BOOL ResetEvent (HANDLE hEvent;
BOOL PulseEvent (HANDLE hEvent)
Поток может перевести событие в сигнальное состояние, использовав функцию SetEvent. Если событие сбрасывается автоматически, единственный (возможно, из многих) ожидающий поток освобождается, а событие автоматически переводится в несигнальное состояние. Если для данного события не выполняет ожидание ни один из потоков, оно остается в сигнальном состоянии до момента, когда поток начнет ожидание, после чего он немедленно освобождается. Отметим, что тот же результат можно получить, использовав семафор с максимальным значением счетчика 1.
Если же, с другой стороны, событие сбрасывается вручную, оно остается в сигнальном состоянии до тех пор, пока поток не вызовет функцию ResetEvent для данного события. В этот промежуток времени все ожидающие потоки освобождаются и возможно, что поток начнет ожидание и будет освобожден до сброса события.
Функция PulseEvent освобождает все события, выполняющие ожидание для данного события с ручным сбросом, которое затем сбрасывается автоматически. В случае события с автосбросом функция PulseEvent освобождает единственное ожидающее событие, если таковое существует.
Отметим, что функция ResetEvent используется только после того, как событие с ручным сбросом будет переведено в сигнальное состояние функцией SetEvent. Будьте осторожны при использовании функции WaitForMultipleObjects для ожидание всех событий, которые должны перейти в сигнальное состояние. Ожидающий поток будет освобожден, только когда все события одновременно окажутся в сигнальном состоянии, а некоторые из событий могут быть сброшены из сигнального состояния до освобождения ожидающего потока.
Обзор: четыре модели использования событий
Комбинирование устанавливаемых вручную и автоматически событий с функциями SetEvent и PulseEvent дает четыре различных пути использования событий.
Предупреждение: при неверном использовании события могут привести к возникновению состояния гонок, зависаниям и другим незаметным и трудно выявляемым ошибкам. В таблице описаны четыре возможные ситуации.
Событие с автоматическим сбросом похоже на дверь с пружиной, которая ее захлопывает, тогда как событие с ручным сбросом не имеет пружины, и поэтому так и остается открытым. Если продолжить аналогию, то функция PulseEvent открывает дверь и немедленно закрывает ее после того, как один (для автосброса) или все (для сброса вручную) ожидающие потоки пройдут через дверь. Функция SetEvent открывает дверь и оставляет ее открытой.
Резюме по использованию событий
|
События с автосбросом |
События с ручным сбросом |
Функция SetEvent |
Освобождается один поток. Если ни один поток в данный момент не выполняет ожидание для данного события, первый же поток, который начнет ожидание в дальнейшем, будет немедленно освобожден. Событие будет сброшено автоматически |
Все потоки, ожидающие в данный момент, освобождаются. Событие остается в сигнальном состоянии до тех пор, пока не будет сброшено каким-то потоком |
Функция PulseEvent |
Освобождается один поток, но только в случае, если поток в данный момент выполняет ожидание для данного события |
Все ожидающие в данный момент потоки, если такие есть, освобождаются, а событие затем сбрасывается. Если нет ни одного ожидающего потока, событие остается в состоянии сигнала до тех пор, пока поток не начнет ожидание для него |
5.2 Дополнительные сблокированные функции
Далее приведено еще несколько функций, которые позволяют выполнять элементарные операции для сравнения и обмена пар переменных.
Сблокированный обмен записывает одну переменную в другую:
LONG InterlockedExchange ( LPLONG Target, LONG Value)
Функция возвращает текущее значение переменной *Target и присваивает ей значение Value. Переменная Target должна выравниваться по словам.
Функция InterlockedExchangeAdd добавляет к первому значению второе.
LONG InterlockedExchangeAdd ( PLONG Addend, LONG Increment)
Переменная Increment прибавляется к переменной *Addend, и возвращается исходное значение *Addend. Эта функция позволяет выполнить атомарную операцию увеличения переменной на 2 (или большее число), что невозможно сделать последовательными вызовами функции InterlockedIncrement.
Последняя функция, InterlockedCompareExchange, аналогична функции InterlockedExchange, за исключением того, что обмен возможен только в том случае, если равенство выполняется.
PVOID InterlockedCompareExchange ( PVOID *Destination,
PVOID Exchange, PVOID Comparand)
Эта функция выполняет в атомарной операции следующие действия (причина использования типа pvoid для двух последних параметров непонятна):
Temp = *Destination;
if (*Destination == Comparand) *Destination = Exchange;
return Temp;
Одно из применений этой функции — блокировка для реализации критической секции кода. Переменная *Destination является "переменной блокировки", для которой 1 значит "разблокировано", а 0 — "заблокировано". Переменная Exchange должна иметь значение 0, a Comparand — значение 1. Вызвавший функцию поток получает во "владение" критическую секцию, если функция возвращает значение 1. Иначе он должен "заснуть" или "зациклиться" — выполнять бесполезный цикл некоторое время, а затем попробовать снова. Это зацикливание — именно то, что делает функция EnterCriticalSection во время ожидания для объекта CRITICAL_SECTION с ненулевым значением счетчика цикла.
Лекция 6. Тема: Управление памятью. Использование виртуальной памяти
Архитектура управления памятью.
Каждый процесс Win32 имеет собственное виртуальное адресное пространство размером 4Гбайт (232 байт). Win32 делает доступной процессу по меньшей мере его половину (2Гбайт). Остальная часть виртуального адресного пространства предназначена для совместно используемых данных и кода, системного кода, драйверов и т.п.
Обзор управления памятью.
Операционная система управляет всеми элементами отображения виртуальной памяти в физическую, механизмом подкачки страниц, обменом страниц по запросу и т.д. Вот краткое резюме.
Система имеет сравнительно малый объем физической памяти.
Каждый процесс – а пользовательских и системных процессов может быть несколько – имеет собственное виртуальное адресное пространство, которое может намного превышать доступную физическую память
Операционная система отображает виртуальные адреса в физические.
Большая часть виртуальных страниц не будет присутствовать в физической памяти, поэтому ОС следит за страничными ошибками (обращениями к страницам, отсутствующим в оперативной памяти) и загружает информацию с диска – либо из системного файла подкачки, либо из обычного файла. Страничные ошибки, хотя и незаметны программисту, влияют на быстродействие, поэтому программы должны проектироваться таким образом, чтобы их количество было сведено к минимуму.
На рис. 6.1 показан механизм управления памятью в API Win32, основанный на диспетчере виртуальной память (Virtual Memory Manager). API виртуальной памяти Win32 (функции VirtualAlloc, VirtualFree, VirtualLock, VirtualUnlock и т.д. работает с целыми страницами. API “кучи” Win32 может работать с единицами память, определяемыми пользователем.
Функция VitualAlloc распределяет ряда страниц в виртуальном адресном пространстве, а функция VitualAllocEx распределяет ряд страниц в виртуальном адресном пространстве указанного процесса.
LPVOID VitualAlloc ( LPVOID lpvAddress, DWORD dwSize,
DWORD dwAllocationType, DWORD dwProtect).
LPVOID VitualAllocEx ( HANDLE hProcess, LPVOID lpvAddress,
DWORD dwSize, DWORD dwAllocationType, DWORD dwProtect).
Функция VirtualFree освобождает ряд страниц в виртуальном адресном пространстве. А функция VirtualFreeEx освобождает ряд страниц в виртуальном адресном пространстве указанного процесса.
BOOL VirtualFree(LPVOID lpvAddress, DWORD dwSize, DWORD dwFreeType)
BOOL VirtualFreeEx(HANDLE hProcess, LPVOID lpvAddress, DWORD dwSize,
DWORD dwFreeType)
Функция VirtualLock блокирует область виртуального адресного пространства в памяти. А функция VirtualUnLock дает возможность разблокировать указанный ряд страниц в виртуальном адресном пространстве процесса, позволяя системе выгружать эти страницы в файл подкачки по мере необходимости.
BOOL VirtualLock(LPVOID lpvAddress, DWORD dwSize),
BOOL VirtualUnlock(LPVOID lpvAddress, DWORD dwSize)
Функция VirtualProtect изменяет установки защиты доступа к области выделенных страниц в виртуальном адресном пространстве. Функция VirtualProtectEx может действовать в виртуальном адресном пространстве других процессов, тогда как VirtualProtect действует толька в рамках вызывающего процесса.
BOOL VirtualProtect(LPVOID lpvAddress, DWORD dwSize, DWORD dwNewProtect,
DWORD pdwOldProtect)
BOOL VirtualProtectEx(HANDLE hProcess, LPVOID lpvAddress, DWORD dwSize,
DWORD dwNewProtect, DWORD pdwOldProtect)
Лекция 7. Тема: Динамически распределяемая память