- •WINDOWS
- •Джеффри Рихтер
- •ЧАCTЬ I МАТЕРИАЛЫ ДЛЯ ОБЯЗАТЕЛЬНОГО ЧТЕНИЯ
- •ГЛАВА 1. Обработка ошибок
- •Вы тоже можете это сделать
- •Программа-пример ErrorShow
- •ГЛАВА 2 Unicode
- •Наборы символов
- •Одно- и двухбайтовые наборы символов
- •Unicode: набор широких символов
- •Почему Unicode?
- •Windows 2000 и Unicode
- •Windows 98 и Unicode
- •Windows CE и Unicode
- •В чью пользу счет?
- •Unicode и СОМ
- •Как писать программу с использованием Unicode
- •Unicode и библиотека С
- •Типы данных, определенные в Windows для Unicode
- •Unicode- и ANSI-функции в Windows
- •Строковые функции Windows
- •Ресурсы
- •Текстовые файлы
- •Перекодировка строк из Unicode в ANSI и обратно
- •ГЛАВА 3 Объекты ядра
- •Что такое объект ядра
- •Учет пользователей объектов ядра
- •Защита
- •Таблица описателей объектов ядра
- •Создание объекта ядра
- •Закрытие объекта ядра
- •Совместное использование объектов ядра несколькими процессами
- •Наследование описателя объекта
- •Изменение флагов описателя
- •Именованные объекты
- •Пространства имен Terminal Server
- •Дублирование описателей объектов
- •ЧАСТЬ II НАЧИНАЕМ РАБОТАТЬ
- •ГЛАВА 4 Процессы
- •Ваше первое Windows-приложение
- •Описатель экземпляра процесса
- •Описатель предыдущего экземпляра процесса
- •Командная строка процесса
- •Переменные окружения
- •Привязка к процессорам
- •Режим обработки ошибок
- •Текущие диск и каталог для процесса
- •Текущие каталоги для процесса
- •Определение версии системы
- •Функция CreateProcess
- •Параметры pszApplicationName и pszCommandLine
- •Параметры psaProcess, psaThread и blnheritHandles
- •Параметр fdwCreate
- •Параметр pvEnvironment
- •Параметр pszCurDir
- •Параметр psiStartlnfo
- •Параметр ppiProclnfo
- •Завершение процесса
- •Возврат управления входной функцией первичного потока
- •Функция ExitProcess
- •Функция TerminateProcess
- •Когда все потоки процесса уходят
- •Что происходит при завершении процесса
- •Дочерние процессы
- •Запуск обособленных дочерних процессов
- •Перечисление процессов, выполняемых в системе
- •Программа-пример Processlnfo
- •ГЛАВА 5 Задания
- •Определение ограничений, налагаемых на процессы в задании
- •Включение процесса в задание
- •Завершение всех процессов в задании
- •Получение статистической информации о задании
- •Уведомления заданий
- •Программа-пример JobLab
- •ГЛАВА 6 Базовые сведения о потоках
- •В каких случаях потоки создаются
- •И в каких случаях потоки не создаются
- •Ваша первая функция потока
- •Функция CreateThread
- •Параметр psa
- •Параметр cbStack
- •Параметры pfnStartAddr и pvParam
- •Параметр fdwCreate
- •Параметр pdwThreadlD
- •Завершение потока
- •Возврат управления функцией потока
- •Функция ExitThread
- •Функция TerminateThread
- •Если завершается процесс
- •Что происходит при завершении потока
- •Кое-что о внутреннем устройстве потока
- •Некоторые соображения по библиотеке С/С++
- •Ой, вместо _beginthreadex я по ошибке вызвал CreateThread
- •Библиотечные функции, которые лучше не вызывать
- •Как узнать о себе
- •Преобразование псевдоописателя в настоящий описатель
- •ГЛАВА 7 Планирование потоков, приоритет и привязка к процессорам
- •Приостановка и возобновление потоков
- •Приостановка и возобновление процессов
- •Функция Sleep
- •Переключение потоков
- •Определение периодов выполнения потока
- •Структура CONTEXT
- •Приоритеты потоков
- •Абстрагирование приоритетов
- •Программирование приоритетов
- •Динамическое изменение уровня приоритета потока
- •Подстройка планировщика для активного процесса
- •Программа-пример Scheduling Lab
- •Привязка потоков к процессорам
- •ГЛАВА 8 Синхронизация потоков в пользовательском режиме
- •Кэш-линии
- •Более сложные методы синхронизации потоков
- •Худшее, что можно сделать
- •Критические секции
- •Критические секции: важное дополнение
- •Критические секции и спин-блокировка
- •Критические секции и обработка ошибок
- •Несколько полезных приемов
- •Не занимайте критические секции надолго
- •ГЛАВА 9 Синхронизация потоков с использованием объектов ядра
- •Wait-функции
- •Побочные эффекты успешного ожидания
- •События
- •Программа-пример Handshake
- •Ожидаемые таймеры
- •Ожидаемые таймеры и АРС-очередь
- •И еще кое-что о таймерах
- •Семафоры
- •Мьютексы
- •Отказ от объекта-мьютекса
- •Мьютексы и критические секции
- •Программа-пример Queue
- •Сводная таблица объектов, используемых для синхронизации потоков
- •Другие функции, применяемые в синхронизации потоков
- •Асинхронный ввод-вывод на устройствах
- •Функция WaitForlnputldle
- •Функция MsgWaitForMultipleObjects(Ex)
- •Функция WaitForDebugEvent
- •Функция SignalObjectAndWait
- •ГЛАВА 10 Полезные средства для синхронизации потоков
- •Реализация критической секции: объект-оптекс
- •Программа-пример Optex
- •Создание инверсных семафоров и типов данных, безопасных в многопоточной среде
- •Программа-пример lnterlockedType
- •Синхронизация в сценарии "один писатель/группа читателей"
- •Программа-пример SWMRG
- •Реализация функции WaitForMultipleExpressions
- •Программа-пример WaitForMultExp
- •ГЛАВА 11 Пулы потоков
- •Сценарий 1: асинхронный вызов функций
- •Сценарий 2: вызов функций через определенные интервалы времени
- •Программа-пример TimedMsgBox
- •Сценарий 3: вызов функций при освобождении отдельных объектов ядра
- •Сценарий 4; вызов функций по завершении запросов на асинхронный ввод-вывод
- •ГЛАВА 12 Волокна
- •Работа с волокнами
- •Программа-пример Counter
- •ЧАСТЬ III УПРАВЛЕНИЕ ПАМЯТЬЮ
- •Виртуальное адресное пространство процесса
- •Как адресное пространство разбивается на разделы
- •Увеличение раздела для кода и данных пользовательского режима до 3 Гб на процессорах x86 (только Windows 2000)
- •Закрытый раздел размером 64 Кб (только Windows 2000)
- •Раздел для общих MMF (только Windows 98)
- •Регионы в адресном пространстве
- •Передача региону физической памяти
- •Физическая память и страничный файл
- •Физическая память в страничном файле не хранится
- •Атрибуты защиты
- •Защита типа «копирование при записи»
- •Специальные флаги атрибутов защиты
- •Подводя итоги
- •Блоки внутри регионов
- •Особенности адресного пространства в Windows 98
- •Выравнивание данных
- •ГЛАВА 14 Исследование виртуальной памяти
- •Системная информация
- •Программа-пример Syslnfo
- •Статус виртуальной памяти
- •Программа-пример VMStat
- •Определение состояния адресного пространства
- •Функция VMQuery
- •Программа-пример VMMap
- •ГЛАВА 15 Использование виртуальной памяти в приложениях
- •Резервирование региона в адресном пространстве
- •Передача памяти зарезервированному региону
- •Резервирование региона с одновременной передачей физической памяти
- •В какой момент региону передают физическую память
- •Возврат физической памяти и освобождение региона
- •В какой момент физическую память возвращают системе
- •Программа-пример VMAIloc
- •Изменение атрибутов защиты
- •Сброс содержимого физической памяти
- •Программа-пример MemReset
- •Механизм Address Windowing Extensions (только Windows 2000)
- •Программа-пример AWE
- •ГЛАВА 16 Стек потока
- •Стек потока в Windows 98
- •Функция из библиотеки С/С++ для контроля стека
- •Программа-пример Summation
- •ГЛАВА 17 Проецируемые в память файлы
- •Проецирование в память EXE- и DLL-файлов
- •Статические данные не разделяются несколькими экземплярами EXE или DLL
- •Программа-пример Applnst
- •Файлы данных, проецируемые в память
- •Метод 1: один файл, один буфер
- •Метод 2: два файла, один буфер
- •Метод 3: один файл, два буфера
- •Метод 4: один файл и никаких буферов
- •Использование проецируемых в память файлов
- •Этап1: создание или открытие объекта ядра «файл»
- •Этап 2: создание объекта ядра «проекция файла»
- •Этап 3: проецирование файловых данных на адресное пространство процесса
- •Этап 4: отключение файла данных от адресного пространства процесса
- •Этапы 5 и 6: закрытие объектов «проекция файла» и «файл»
- •Программа-пример FileRev
- •Обработка больших файлов
- •Проецируемые файлы и когерентность
- •Базовый адрес файла, проецируемого в память
- •Особенности проецирования файлов на разных платформах
- •Совместный доступ процессов к данным через механизм проецирования
- •Файлы, проецируемые на физическую память из страничного файла
- •Программа-пример MMFShare
- •Частичная передача физической памяти проецируемым файлам
- •Программа-пример MMFSparse
- •ГЛАВА 18 Динамически распределяемая память
- •Стандартная куча процесса
- •Дополнительные кучи в процессе
- •Защита компонентов
- •Более эффективное управление памятью
- •Локальный доступ
- •Исключение издержек, связанных с синхронизацией потоков
- •Быстрое освобождение всей памяти в куче
- •Создание дополнительной кучи
- •Выделение блока памяти из кучи
- •Изменение размера блока
- •Определение размера блока
- •Освобождение блока
- •Уничтожение кучи
- •Использование куч в программах на С++
- •Другие функции управления кучами
- •ЧАСТЬ IV ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
- •ГЛАВА 19 DLL: основы
- •DLL и адресное пространство процесса
- •Общая картина
- •Создание DLL-модуля
- •Что такое экспорт
- •Создание DLL для использования с другими средствами разработки (отличными от Visual C++)
- •Создание ЕХЕ-модуля
- •Что такое импорт
- •Выполнение ЕХЕ-модуля
- •ГЛАВА 20 DLL: более сложные методы программирования
- •Явная загрузка DLL и связывание идентификаторов
- •Явная загрузка DLL
- •Явная выгрузка DLL
- •Явное подключение экспортируемого идентификатора
- •Функция входа/выхода
- •Уведомление DLL_PROCESS_ATTACH
- •Уведомление DLL_PROCESS_DETACH
- •Уведомление DLL_THREAD_ATTACH
- •Уведомление DLL_THREAD_DETACH
- •Как система упорядочивает вызовы DIIMain
- •Функция DllMain и библиотека С/С++
- •Отложенная загрузка DLL
- •Программа-пример DelayLoadApp
- •Переадресация вызовов функций
- •Известные DLL
- •Перенаправление DLL
- •Модификация базовых адресов модулей
- •Связывание модулей
- •ГЛАВА 21 Локальная память потока
- •Динамическая локальная память потока
- •Использование динамической TLS
- •Статическая локальная память потока
- •Пример внедрения DLL
- •Внедрение DLL c использованием реестра
- •Внедрение DLL с помощью ловушек
- •Утилита для сохранения позиций элементов на рабочем столе
- •Внедрение DLL с помощью удаленных потоков
- •Программа-пример lnjLib
- •Библиотека lmgWalk.dll
- •Внедрение троянской DLL
- •Внедрение DLL как отладчика
- •Внедрение кода в среде Windows 98 через проецируемый в память файл
- •Внедрение кода через функцию CreateProcess
- •Перехват API-вызовов: пример
- •Перехват API-вызовов подменой кода
- •Перехват API-вызовов с использованием раздела импорта
- •Программа-пример LastMsgBoxlnfo
- •ЧАСТЬ V СТРУКТУРНАЯ ОБРАБОТКА ИСКЛЮЧЕНИЙ
- •ГЛАВА 23 Обработчики завершения
- •Примеры использования обработчиков завершения
- •Funcenstein1
- •Funcenstein2
- •Funcenstein3
- •Funcfurter1
- •Проверьте себя: FuncaDoodleDoo
- •Funcenstein4
- •Funcarama1
- •Funcarama2
- •Funcarama3
- •Funcarama4: последний рубеж
- •И еще о блоке finally
- •Funcfurter2
- •Программа-пример SEHTerm
- •ГЛАВА 24 Фильтры и обработчики исключений
- •Примеры использования фильтров и обработчиков исключений
- •Funcmeister1
- •Funcmeister2
- •EXCEPTION_EXECUTE_HANDLER
- •Некоторые полезные примеры
- •Глобальная раскрутка
- •Остановка глобальной раскрутки
- •EXCEPTION_CONTINUE_EXECUTION
- •Будьте осторожны с EXCEPTION_CONTINUE_EXECUTION
- •EXCEPTION_CONTINUE_SEARCH
- •Функция GetExceptionCode
- •Функция GetExceptionlnformation
- •Программные исключения
- •ГЛАВА 25 Необработанные исключения и исключения С++
- •Отладка по запросу
- •Отключение вывода сообщений об исключении
- •Принудительное завершение процесса
- •Создание оболочки вокруг функции потока
- •Создание оболочки вокруг всех функций потоков
- •Автоматический вызов отладчика
- •Явный вызов функции UnhandledExceptionFilter
- •Функция UnhandledExceptionFilter изнутри
- •Исключения и отладчик
- •Программа-пример Spreadsheet
- •Исключения С++ и структурные исключения
- •Перехват структурных исключений в С++
- •ЧАСТЬ VI ОПЕРАЦИИ С ОКНАМИ
- •ГЛАВА 26 Оконные сообщения
- •Очередь сообщений потока
- •Посылка асинхронных сообщений в очередь потока
- •Посылка синхронных сообщений окну
- •Пробуждение потока
- •Флаги состояния очереди
- •Алгоритм выборки сообщений из очереди потока
- •Пробуждение потока с использованием объектов ядра или флагов состояния очереди
- •Передача данных через сообщения
- •Программа-пример CopyData
- •ГЛАВА 27 Модель аппаратного ввода и локальное состояние ввода
- •Поток необработанного ввода
- •Локальное состояние ввода
- •Ввод с клавиатуры и фокус
- •Управление курсором мыши
- •Подключение к очередям виртуального ввода и переменным локального состояния ввода
- •Программа-пример LISLab
- •Программа-пример LISWatch
#else
#error Module contains CPU-specific code, modify and recompile. #endif
//вносим изменения в регистры потока, ContextFlags
//можно и не инициализировать, так как это уже сделано
Context.ConlrolFlags = CONTEXT_CONTROL; SetThreadContext(hThread, &Context);
//возобновляем выполнение потока; оно начнется с адреса
0x00010000
ResumeThread(hThread);
Этот код, вероятно, приведет к ошибке защиты (нарушению доступа) в удаленном потоке; система сообщит о необработанном исключении, и удаленный процесс бу дет закрыт. Все верно — нс Ваш, а удаленный. Вы благополучно обрушили другой процесс, оставив свой в целости и сохранности!
Функции GetTbreadContexf и SetThreadContext наделяют Вас огромной властью над потоками, но пользоваться ею нужно с осторожностью. Вызывают их лишь считан ные приложения. Эти функции предназначены для отладчиков и других инструмен тальных средств, хотя обращаться к ним можно из любых программ
Подробнее о структуре CONTEXT мы поговорим в главе 24.
Приоритеты потоков
В начале главы я сказал, что поток получает доступ к процессору на 20 мс, после чего планировщик переключает процессор на выполнение другого потока. Так происхо дит, только если у всех потоков один приоритет, но на самом деле в системе суще ствуют потоки с разными приоритетами, а это меняет порядок распределения про цессорного времени.
Каждому потоку присваивается уровень приоритета — от 0 (самый низкий) до 31 (самый высокий). Решая, какому потоку выделить процессорное премя, система сна чала рассматривает только потоки с приоритетом 31 и подключает их к процессору по принципу карусели. Если поток с приоритетом 31 нс исключен из планирования, он немедленно получает квант времени, по истечении которого система проверяет, есть ли еще один такой поток. Если да, он тоже получает свой квант процессорного времени.
Пока в системе имеются планируемые потоки с приоритетом 31, ни один поток с более низким приоритетом процессорного времени не получает. Такая ситуация на зывается "голоданием* (starvation). Она наблюдается, когда потоки с более высоким приоритетом так интенсивно используют процессорное время, что остальные прак тически не работают. Вероятность этой ситуации намного ниже в многопроцессор ных системах, где потоки с приоритетами 31 и 30 могут выполняться одновременно. Система всегда старается, чтобы процессоры были загружены работой, и они проста ивают только в отсутствие планируемых потоков.
На первый взгляд, в системе, организованной таким образом, у потоков с низким приоритетом нет ни единого шанса на исполнение. Но, как я уже говорил, зачастую потоки как раз и не нужно выполнять. Например, если первичный поток Вашего про цесса
вызывает GetMessage, а система видит, что никаких сообщений пока нет, она приостанавливает его выполнение, отнимает остаток неиспользованного времени и тут же подключает к процессору другой ожидающий поток. И пока в системе не по явятся сообщения для потока Вашего процесса, он будет простаивать — система не станет тратить на него процессорное время. Но вот в очереди этого потока появля ется сообщение, и система сразу же подключает его к процессору (если только в этот момент не выполняется поток с более высоким приоритетом).
А теперь обратите внимание на еще один момент. Потоки с более высоким при оритетом всегда вытесняют потоки с более низким приоритетом независимо от того, исполняются последние или нет. Допустим, процессор исполняет поток с приорите том 5, и тут система обнаруживает, что поток с более высоким приоритетом готов к выполнению. Что будет? Система остановит поток с более низким приоритетом — даже ссли не истек отведенный ему квант процессорного времени — и подключит к процессору поток с более высоким приоритетом (и, между прочим, выдаст ему пол ный квант времени),
Кстати, при загрузке системы создается особый поток — поток обнуления стра ниц (zero page thread), которому присваивается нулевой уровень приоритета. Ни один поток, кроме этого, не может иметь нулевой уровень приоритета Он обнуляет сво бодные страницы в оперативной памяти при отсутствии других потоков, требующих внимания со стороны системы.
Абстрагирование приоритетов
Создавая планировщик потоков, разработчики из Microsoft прекрасно понимали, что он не подойдет на все случаи жизни. Они также осознавали, что со временем "назна чение" компьютера может измениться Например, в момент выпуска Windows NT со здание приложений с поддержкой OLE еще только начиналось. Теперь такие прило жения — обычное дело. Кроме того, значительно расширилось применение игрово го программного обеспечения, ну и, конечно же, Интернета
Алгоритм планирования потоков существенно влияет на выполнение приложений. С самого начала разработчики Microsott понимали, что его придется изменять по мере того, как будут расширяться сферы применения компьютеров Microsoft гарантирует, что наши программы будут работать и в следующих версиях Windows. Как же ей уда ется изменять внутреннее устройство системы, не нарушая работоспособность наших программ? Ответ в том, что:
•планировщик документируется не полностью;
•Microsoft не разрешает в полной мере использовать все особенности плани ровщика;
•Microsoft предупреждает, что алгоритм работы планировщика постоянно ме няется, и не рекомендует писать программы в расчете на текущий алгоритм
Windows API предоставляет слой абстрагирования от конкретного алгоритма ра боты планировщика, запрещая прямое обращение к планировщику. Вместо этого Вы вызываете функции Windows, которые "интерпретируют" Ваши параметры в зависи мости от версии системы, Я буду рассказывать именно об этом слое аборагирования
Проектируя свое приложение, Вы должны учитывать возможность параллельного выполнения других программ. Следовательно, Вы обязаны выбирать класс приорите та, исходя из того, насколько "отзывчивой" должна быть Ваша программа. Согласен, такая формулировка довольно туманна, но так и задумано: Microsoft не желает обе щать ничего такого, что могло бы нарушить работу Вашего кода в будущем.
Windows поддерживает шесть классов приоритета; idle (простаивающий), below normal (ниже обычного), normal (обычный), above normal (выше обычного), high (вы сокий) и realtime (реального времени). Самый распространенный класс приоритета, естественно, — normal; его использует 99% приложений. Классы приоритета показа ны в следующей таблице.
Класс приоритета
Real-lime
High
Above normal
Normal
Below normal
Idle
Описание
Потоки в этом процессе обязаны немедленно реагировать на события, обеспечивая выполнение критических по времени задач. Такие потоки вытесняют даже компоненты операционной системы Будьте крайне осторожны с этим классом.
Потоки в этом процессе тоже должны немедленно реагировать на со бытия, обеспечивая выполнение критических по времени задач Этот класс присвоен, например, Task Manager, что дает возможность пользо вателю закрывать больше неконтролируемые процессы
Класс приоритета, промежуточный между normal и high. Это новый класс, введенный в Windows 2000.
Потоки в этом процессе не предъявляют особых требований к выделе нию им процессорного времени.
Класс приоритета, промежуточный между normal и idle. Это новый класс, введенный в Windows
2000.
Потоки в этом процессе выполняются, когда система не занята другой работой Этот класс приоритета обычно используется для утилит, ра ботающих в фоновом режиме, экранных заставок и приложений, собирающих статистическую информацию
Приоритет idle идеален для программ, выполняемых, только когда системе боль ше нечего делать, Примеры таких программ — экранные заставки и средства мони торинга. Компьютер, не используемый в интерактивном режиме, может быть занят другими задачами (действуя, скажем, в качестве файлового сервера), и их потокам незачем конкурировать с экранной заставкой за доступ к процессору. Средства мо ниторинга, собирающие статистическую информацию о системе, тоже не должны мешать выполнению более важных задач
Класс приоритета high следует использовать лишь при крайней необходимости Может, Вы этого и нс знаете, но Explorer выполняется с высоким приоритетом. Боль шую часть времени его потоки простаивают, готовые пробудиться, кактолько пользо ватель нажмет какую-нибудь клавишу или щелкнет кнопку мыши. Пока потоки Explorer простаивают, система не выделяет им процессорное время, что позволяет выполнять потоки с более низким приоритетом Но вот пользователь нажал, скажем, Ctrl+Esc, и система пробуждает поток Explorer. (Комбинация клавиш Ctrl+Esc попутно открыва ет меню Start.) Если в данный момент исполняются потоки с более низким приори тетом, они немедленно вытесняются, и начинает работать поток Explorer Microsoft разработала Explorer именно так потому, что любой пользователь — независимо от текущей ситуации в системе — ожидает мгновенной реакции оболочки на свои ко манды R сущности, окна Explorcr можно открывать, даже когда все потоки с более низким приоритетом зависают в бесконечных циклах Обладая более высоким при оритетом, потоки Explorer вытесняют поток, исполняющий бесконечный цикл, и дают возможность закрыть зависший процесс.
Надо отметить высокую степень продуманности Explorer. Основную часть време ни он просто "спит", не требуя процессорного времени. Будь это не так, вся система работала бы гораздо медленнее, а многие приложения просто не отзывались бы на действия пользователя
Классом приоритета real-time почти никогда не стоит пользоваться На самом деле в ранних бета-версиях Windows NT 3.1 присвоение этого класса приоритета прило жениям даже не предусматривалось, хотя операционная система поддерживала эту возможность. Real-time — чрезвычайно высокий приоритет, и, поскольку большин ство потоков в системе (включая управляющие самой системой) имеет более низкий приоритет, процесс с таким классом окажет на них сильное влияние. Так, потоки реального времени могут заблокировать необходимые операции дискового и сетевого ввода-вывода и привести к несвоевременной обработке ввода от мыши и клавиату ры — пользователь может подумать, что система зависла. У Вас должна быть очень веская причина для применения класса real-time — например, программе требуется
реагировать на события в аппаратных средствах с минимальной задержкой или вы полнять быстротечную операцию, которую нельзя прерывать ни при каких обстоя тельствах
NOTE:
Процесс с классом приоритета real-time нельзя запустить, если пользователь не имеет привилегии Increase Scheduling Priority. По умолчанию такой привилеги ей обладает администратор и пользователь с расширенными полномочиями.
Конечно, большинство процессов имеет обычный класс приоритета. В Windows 2000 появилось два новых промежуточных класса — below normal и above normal Microsoft добавила их, поскольку некоторые компании жаловались, что существующий набор классов приоритетов не дает должной гибкости.
Выбрав класс приоритета, забудьте о том, как Ваша программа будет выполняться совместно с другими приложениями, и сосредоточьтесь на ее потоках. Windows под держивает семь относительных приоритетов потоков: idle (простаивающий), lowcst (низший), below normal (ниже обычного), normal (обычный), above normal (выше обычного), highest (высший) и time-critical (критичный по времени) Эти приорите ты относительны классу приоритета процесса Как обычно, большинство потоков использует обычный приоритет. Относительные приоритеты потоков описаны в сле дующей таблице.
Относительный |
Описание |
приоритет потока |
|
Time-critical |
Поток выполняется с приоритетом 31 в классе real-time и с |
|
приоритетом 15 в других классах |
|
|
Highest |
Поток выполняется с приоритетом на два уровня выше |
|
обычною для данного класса |
|
|
Above normal |
Поток выполняется с приоритетом на один уровень выше |
|
обычного для данного класса |
|
|
Normal |
Поток выполняется с обычным приоритетом процесса для |
|
данного класса |
|
|
Below normal |
Поток выполняется с приоритетом на один уровень ниже |
|
обычного для данного класса |
|
|
Lowest |
Поток выполняется с приоритетом на два уровня ниже |
|
обычного для данного класса |
|
|
Idle |
Поток выполняется с приоритетом 16 в классе real-time и с |
|
приоритетом 1 в других классах |
|
|
Итак, Вы присваиваете процессу некий класс приоритета и можете изменять от носительные приоритеты потоков в пределах процесса. Заметьте, что я не сказал ни слова об уровнях приоритетов 0-31. Разработчики приложений не имеют с ними дела. Уровень приоритета формируется самой системой, исходя из класса приоритета про цесса и относительного приоритета потока, А механизм его формирования — как раз то, чем Microsoft не хочет себя ограничивать И действительно, этот механизм меня ется практически в каждой версии системы.
В следующей таблице показано, как формируется уровень приоритета в Win dows 2000, но не забывайте, что в Windows NT и тем более в Windows 95/98 этот механизм действует несколько иначе Учтите также, что в будущих версиях Windows он вновь изменится.
Например, обычный поток в обычном процессе получает уровень приоритета 8, Поскольку большинство процессов имеет класс normal, a большинство потоков —
относительный приоритет normal, y основной части потоков в системе уровень при оритета равен 8.
Обычный поток в процессе с классом приоритета high получает уровень приори тета 13. Изменив класс приоритета процесса на idle, Вы снизите уровень приоритета того же потока до 4. Вспомните, что приоритет потока всегда относителен классу приоритета его процесса Изменение класса приоритета процесса не влияет на от носительные приоритеты его потоков, но сказывается на уровне их приоритета
Относительный приоритет потока |
Idle |
Класс приоритета процесса |
Real- |
|||
|
|
|
|
|
|
time |
|
|
Below |
Normal |
Above |
High |
|
|
|
normal |
|
normal |
|
|
|
|
|
|
|
|
|
Time-critical (критичный по времени) |
15 |
15 |
15 |
15 |
15 |
31 |
|
|
|
|
|
|
|
Highest (высший) |
6 |
8 |
10 |
12 |
15 |
26 |
|
|
|
|
|
|
|
Above normal (выше обычного) |
5 |
7 |
9 |
11 |
14 |
25 |
|
|
|
|
|
|
|
Normal (обычный) |
4 |
6 |
8 |
10 |
13 |
24 |
|
|
|
|
|
|
|
Below normal (ниже обычного) |
3 |
5 |
7 |
9 |
12 |
23 |
|
|
|
|
|
|
|
Lowest (низший) |
2 |
4 |
6 |
8 |
11 |
22 |
|
|
|
|
|
|
|
Idle (простаивающий) |
1 |
1 |
1 |
1 |
1 |
16 |
|
|
|
|
|
|
|
Обратите внимание, что в таблице не показано, как задать уровень приоритета 0. Это связано с тем, что нулевой приоритет зарезервирован для потока обнуления стра ниц, и никакой другой поток не может иметь такой приоритет. Кроме того, уровни 17-21 и 27-30 в обычном приложении тоже недоступны. Вы можете пользоваться ими, только если пишете драйвер устройства, работающий в режиме ядра. И еще одно: уровень приоритета потока в процессе с классом real-time не может опускаться ниже 16, а потока в процессе с любым другим классом — подниматься выше 15.
NOTE
Концепция класса приоритета вводит некоторых в заблуждение. Они делают отсюда вывод, будто процессы участвуют в распределении процессорного вре мени. Так вот, процессы никогда не получают процессорное время — оно вы