4. CreateThread уведомляет подсистему Windows о создании нового потока, и та выполняет некоторые подготовительные операции.
5. Вызвавшему коду возвращаются описатель и идентификатор потока (сгенерированный на этапе 3).
6. Выполнение потока возобновляется, и ему может быть выделено процессорное время, если только он не был создан с флагом CREATE_SUSPENDED. Перед вызовом по пользовательскому стартовому адресу поток выполняет операции, описанные в разделе «Этап 3: создание первичного потока, его стека и контекста» ранее в этой главе.
He только оснастка Performance, но и другие утилиты (таблица 6-13) позволяют получать сведения о состоянии потоков в Windows. (Утилиты, показывающие информацию о планировании потоков, перечисляются в разделе «Планирование потоков» далее в этой главе.)
ПРИМЕЧАНИЕ Чтобы получить информацию о потоке с помощью Tlist, введите tlistxxx, где xxx — имя образа процесса или заголовок окна (можно использовать символы подстановки).
Process Explorer позволяет наблюдать за активностью потоков в процессе. Это особенно важно, когда вы пытаетесь понять, почему процесс зависает или запускается какой-то процесс, служащий хостом для множества сервисов (например, Svchost.exe, Dllhost.exe, Inetinfo.exe или System).
Для просмотра потоков в процессе выберите этот процесс и откройте окно его свойств двойным щелчком. Потом перейдите на вкладку Threads. Ha этой вкладке отображается список потоков в процессе. Для каждого потока показывается процентная доля использованного процессорного времени (с учетом заданного интервала обновления), число переключений контекста для данного потока и его стартовый адрес. Поддерживается сортировка по любому из этих трех столбцов.
Новые потоки выделяются зеленым, а существующие — красным. (Длительность подсветки настраивается в Options.) Это помогает обнаруживать создание лишних потоков в процессе. (Как правило, потоки должны создаваться при запуске процесса, а не при каждой обработке какого-либо запроса внутри процесса.)
Когда вы поочередно выбираете потоки в списке, Process Explorer отображает их идентификаторы, время запуска, состояние, счетчики использования процессорного времени, число переключений контекстов, а также базовый и текущий приоритеты. Кнопка KiIl позволяет принудительно завершать индивидуальные потоки, но пользоваться ею следует с крайней осторожностью.
Разница в числе переключений контекста (context switch delta) отражает, сколько раз потоки начинали работать в течение периода обновления, указанного в Process Explorer. Это еще один способ определения активности потоков. B некоторых отношениях он даже лучше, так как многие потоки выполняются в течение лишь очень короткого времени и поэтому крайне редко попадают в список текущих потоков. Например, если вы добавите столбец с разницей в числе переключений контекстов к тому, что показывается для процесса и отсортируете по этому столбцу, то увидите процессы, в которых потоки выполняются, но используют очень мало процессорного времени или вообще его не используют.
Стартовый адрес потока выводится в виде «module\function», где module — имя EXE или DLL. Имя функции извлекается из файла символов для данного модуля (см. эксперимент «Просмотр детальных сведений о процессах с помощью Process Explorer» в главе 1). Если вы точно не знаете, что это за модуль, нажмите кнопку Module, и появится окно свойств модуля, где содержится данная функция.
ПРИМЕЧАНИЕ Для потоков, созданных Windows-функцией Create-Tbread, Process Explorer показывает функцию, переданную в Create-Tbread, а не истинную стартовую функцию потока. Это связано с тем, что все Windows-потоки запускаются в общей стартовой функции-оболочке для процессов или потоков (BaseProcessStartJin6oBaseThre-adStart в Kernel32.dll). Если бы Process Explorer выводил истинный стартовый адрес, то казалось бы, что большинство потоков в процессе были запущены по одному адресу, а это вряд ли помогло бы понять, какой код выполняется потоком.
Однако одного стартового адреса потока может оказаться недостаточно для того, чтобы выяснить, что именно делает поток и какой компонент внутри процесса отвечает за использование процессорного времени этим потоком. Это особенно верно, если стартовый адрес потока относится к универсальной стартовой функции (например, если имя функции не указывает на то, что делает данный поток). Тогда может помочь изучение стека потока. Для его просмотра дважды щелкните интересующий вас поток (или выберите этот поток и нажмите кнопку Stack). Process Explorer покажет стек потока (пользовательского режима и режима ядра, если поток был в последнем режиме).
ПРИМЕЧАНИЕ Отладчики пользовательского режима (Windbg, Ntsd и Cdb) тоже позволяют подключаться к процессу и просматривать стек потока, но Process Explorer выводит стек как пользовательского режима, так и режима ядра простым нажатием одной кнопки. Стеки пользовательского режима и режима ядра можно, но эта утилита гораздо сложнее в использовании. Кстати, при работе Windbg в режиме локальной отладки ядра, поддерживаемом только в Windows XP и Windows Server 2003, увидеть содержимое стеков потоков нельзя.
Просмотр стека потока полезен и при поиске причины зависания процесса. Например, на одной системе Microsoft PowerPoint зависал при запуске на минуту. Чтобы понять причину этого зависания, с помощью Process Explorer изучили стек одного из потоков в процессе. Результат приведен на рис. 6-10.
Как видите, PowerPoint (строка 10) вызвал функцию в Mso.dll (основной Microsoft Office DLL), которая обратилась к функции OpenPrinterWB Winspool.drv (DLL, используемой для подключения к принтерам). Затем Winspool.drv пересылает запрос функции OpenPrinterRPC, а та вызывает функцию в DLL исполняющей среды RPC, сообщая, что запрос посылается удаленному принтеру. Вот так, не зная деталей внутреннего устройства PowerPoint, по именам модулей и функций в стеке потока можно понять, что поток ждет соединения с сетевым принтером. B данной системе был сетевой принтер, который не отвечал, что и объясняет задержку в запуске PowerPoint. (Приложения Microsoft Office соединяются со всеми сконфигурированными принтерами при запуске.) Соединение с тем принтером было удалено из пользовательской системы, и проблема исчезла.
Здесь описываются стратегии и алгоритмы планирования в Windows. B первом разделе этой части материалов рассматриваются принципы планирования в Windows и даются определения ключевых терминов. Уровни приоритета обсуждаются с точки зрения как Windows API, так и ядра. После обзора сопутствующих Windows-функций и утилит подробно анализируются — сначала в однопроцессорных системах, а затем и в многопроцессорных — алгоритмы и структуры данных, используемые подсистемой планирования Windows.
B Windows реализована подсистема вытесняющего планирования на основе уровней приоритета, в которой всегда выполняется поток с наибольшим приоритетом, готовый к выполнению. Однако выбор потока для выполнения может быть ограничен набором процессоров, на которых он может работать. Это явление называется привязкой к процессорам (processor affinity). По умолчанию поток выполняется на любом доступном процессоре, но вы можете изменить привязку к процессорам через Windows-функции планирования, перечисленные в таблице 6-14 (см. далее в этой главе), или заданием маски привязки в заголовке образа.