Если текущий процессор (тот, который пытается определить, что делать с потоком, готовым к выполнению) относится к набору оставшихся простаивающих процессоров, поток планируется к выполнению именно на этом процессоре. A если текущий процессор не входит в список оставшихся простаивающих процессоров, если это система с технологией Hyperthreading и если есть простаивающий логический процессор на физическом, который содержит идеальный процессор для данного потока, то список простаивающих процессоров ограничивается этим набором. B ином случае система проверяет, имеются ли простаивающие логические процессоры на физическом, который содержит предыдущий процессор потока. Если такой набор не пуст, список простаивающих процессоров уменьшается до этого набора.
Из оставшегося набора простаивающих процессоров исключаются все процессоры, находящиеся в состоянии сна. (Эта операция не выполняется, если в ее результате такой список опустел бы.) Наконец, поток подключается к процессору с наименьшим номером в оставшемся списке.
Независимо от версии Windows, как только процессор выбран, соответствующий поток переводится в состояние Standby, и PRCB простаивающего процессора обновляется так, чтобы указывать на этот поток. При выполнении на этом процессоре цикл простоя обнаруживает, что поток выбран и подключает его к процессору.
Выбор процессора для потока в отсутствие простаивающих процессоров
Если простаивающих процессоров нет в момент, когда готовый к выполнению поток переведен в состояние Standby, Windows проверяет приоритет выполняемого потока (или того, который находится в состоянии Standby) и идеальный процессор для него, чтобы решить, следует ли вытеснить выполняемый. B Windows 2000 маска привязки может исключить идеальный процессор. (B Windows XP такое не допускается.) Если этот процессор не входит в маску привязки потока, Windows выбирает для потока процессор с наибольшим номером.
Если для идеального процессора уже выбран поток, ожидающий в состоянии Standby выделения процессорного времени, и его приоритет ниже, чем потока, готовящегося к выполнению, последний вытесняет первый и становится следующим выполняемым на данном процессоре. Если к процессору уже подключен какой-то поток, Windows сравнивает приоритеты текущего и нового потока. Если приоритет текущего меньше, чем нового, первый помечается как подлежащий вытеснению, и Windows ставит в очередь межпроцессорное прерывание, чтобы целевой процессор вытеснил текущий поток в пользу нового.
ПРИМЕЧАНИЕ Windows сравнивает приоритеты текущего и следующего потоков не на всех процессорах, а только на одном, выбранном по только что описанным правилам. Если вытеснение подключенного к данному процессору потока невозможно, новый поток помещается в очередь готовых потоков, соответствующую его уровню приоритета, где он и ждет выделения процессорного времени. Поэтому Windows не гарантирует первоочередное выполнение всех потоков с наивысшим приоритетом, но всегда выполняет один поток с таким приоритетом.
Как мы уже сказали, если готовый поток нельзя выполнить немедленно, он помещается в очередь готовых потоков и ждет выделения процессорного времени. Однако в Windows Server 2003 потоки всегда помещаются в очереди готовых потоков на своих идеальных процессорах.
Выбор потока для выполнения на конкретном процессоре (Windows 2000 и Windows XP)
B некоторых случаях (например, когда поток входит в состояние ожидания, снижает свой приоритет, изменяет привязку, откладывает выполнение или передает управление) Windows нужно найти новый поток для подключения к процессору, на котором работал текущий поток. Как уже говорилось, в однопроцессорной системе Windows просто выбирает первый поток из непустой очереди готовых потоков с наивысшим приоритетом. Ho в многопроцессорной системе Windows 2000 или Windows XP должно быть соблюдено одно из дополнительных условий:
• поток уже выполнялся в прошлый раз на данном процессоре; • данный процессор должен быть идеальным для этого потока; • поток провел в состоянии Ready более трех тактов системного таймера;
• поток имеет приоритет не менее 24.
Таким образом, потоки с жесткой привязкой, в маску которых данный процессор не входит, очевидно, пропускаются. Если потоков, отвечающих одному из условий, нет, Windows отберет поток из начала той очереди готовых потоков, с которой она начинает поиск.
Почему так важно подключить поток именно к тому процессору, на котором он выполнялся в прошлый раз? Как обычно, все дело в быстродействии — процессор, на котором поток выполнялся в прошлый раз, скорее всего еще хранит его данные в своем кэше второго уровня.
Выбор потока для выполнения на конкретном процессоре (Windows Server 2003)
Поскольку в Windows Server 2003 у каждого процессора собственный список потоков, ждущих выполнения на этом процессоре, то по окончании выполнения текущего потока процессор просто проверяет свою очередь готовых потоков. Если его очереди пусты, к процессору подключается поток простоя. Затем этот поток начинает сканировать очереди готовых потоков при других процессорах и ищет потоки, которые можно было бы выполнять на данном процессоре. Заметьте, что в NUMA-системах поток простоя проверяет процессоры сначала в своем узле, а потом в других узлах.
Объекты-задания
Объект «задание» (job object) — это именуемый, защищаемый и разделяемый объект ядра, обеспечивающий управление одним или несколькими процессами как группой. Процесс может входить только в одно задание. По умолчанию его связь с объектом «задание» нельзя разрушить, и все процессы, создаваемые данным процессом и его потомками, будут сопоставлены с тем же заданием. Объект «задание» также регистрирует базовую учетную информацию всех включенных в него процессов, в том числе уже завершившихся. Windows-функции, предназначенные для создания объектов-заданий и манипулирования ими, перечислены в таблице 6-20.
Ниже кратко поясняются некоторые ограничения, которые можно налагать на задания.
• Максимальное число активных процессов Ограничивает число одновременно выполняемых процессов задания.
• Общий лимит на процессорное время в пользовательском режиме Ограничивает максимальное количество процессорного времени, потребляемого процессами задания (с учетом завершившихся) в пользовательском режиме. Как только этот лимит будет исчерпан, все процессы задания завершатся с сообщением об ошибке, а создание новых процессов в задании станет невозможным (если лимит не будет переустановлен). Объект-задание будет переведен в свободное состояние, и все ожидавшие его потоки освободятся. Это поведение системы по умолчанию можно изменить через функцию EndOfJobTimeAction.
• Индивидуальный лимит на процессорное время пользовательского режима для каждого процесса Ограничивает максимальное количество процессорного времени, потребляемого каждым процессом в задании. По достижении этого лимита процесс завершается (не получая шанса на очистку).
• Класс планирования задания Устанавливает длительность кванта для потоков процессов, входящих в задание. Этот параметр применим только в системах, использующих длинные фиксированные кванты (в системах Windows Server по умолчанию). Длительность кванта определяется классом планирования задания, как показано в следующей таблице.
• Привязка задания к процессорам Устанавливает маску привязки к процессорам для каждого процесса задания. (Отдельные потоки могут изменять свои привязки на любое подмножество привязок задания, но процессы этого делать не могут.)
• Класс приоритета для всех процессов задания Определяет класс приоритета для каждого процесса в задании. Потоки не могут повышать свой приоритет относительно класса (как они это обычно делают). Все попытки повышения приоритета игнорируются. (При вызове SetTbreadPriority ошибка не генерируется, но и приоритет не повышается.)
• Минимальный и максимальный размеры рабочего набора по умолчанию Устанавливает указанные минимальный и максимальный размеры рабочего набора для каждого процесса задания. каждого процесса свой рабочий набор, но с одинаковыми максимальным и минимальным размерами.)
• Лимит на виртуальную память, передаваемую процессу или заданию Указывает максимальный размер виртуального адресного пространства, который можно передать либо одному процессу, либо всему заданию.
Задания можно настроить на отправку в очередь объекта «порт завершения ввода-вывода» какого-либо элемента, который могут ждать другие потоки через Windows-функцию GetQueuedCompletionStatus.