Волокна и потоки планировщика пользовательского режима
Поскольку при переключении выполнения с одного потока на другой задействуется планировщик ядра, такая операция может обойтись весьма дорого, особенно если два потока часто переключаются между собой. В Windows реализованы два механизма сокращения «накладных расходов»: волокна и использование планировщика пользовательского режима — "user-mode scheduling (UMS)".
Волокна позволяют приложению осуществлять планирование работы своих собственных «потоков», не полагаясь на встроенный в Windows механизм планирования на основе приоритетов. Волокна часто называют «облегченными» потоками, и, с точки зрения планирования работы, ядру они не видны, поскольку реализуются в пользовательском режиме с помощью библиотеки Kernel32.dll.
Чтобы воспользоваться волокнами, сначала нужно вызвать Windows-функцию преобразования потока в волокно — "ConvertThreadToFiber". Эта функция преобразует поток в запущенное волокно. Впоследствии только что созданное волокно может с помощью функции "CreateFiber" создавать дополнительные волокна. (У каждого волокна может быть свой собственный набор волокон.)
Но в отличие от потока волокно не приступает к выполнению своего кода, пока оно не будет выбрано с помощью функции "SwitchToFiber". Новое волокно выполняется до тех пор, пока оно существует, или до тех пор, пока в нем не будет вызвана функция SwitchToFiber, которая выберет для выполнения другое волокно. Дополнительные сведения можно найти в документации Windows SDK по функциям волокон.
UMS-потоки, доступные только на 64-разрядных версиях Windows, имеют те же основные преимущества, что и волокна, но избавлены от многих недостатков, присущих волокнам. UMS-потоки имеют свое собственное состояние потоков ядра, и поэтому они видимы ядру, которое позволяет нескольким UMS-потокам выдавать блокирующие системные вызовы, совместно использовать и вести борьбу за ресурсы и иметь состояние для каждого потока. Но когда двум и более UMS-потокам требуется работать только в пользовательском режиме, они могут периодически переключать контексты выполнения (за счет уступок одного потока другому) без участия планировщика: переключение контекста происходит в пользовательском режиме. С точки зрения ядра ничего не меняется и продолжается выполнение все того же потока. Когда UMS-поток выполняет операцию, требующую входа в ядро (например, системный вызов), он переключается на выделенный ему поток режима ядра (это называется непосредственным переключением контекста — "directedcontextswitch").
Хотя у потоков имеется свой собственный контекст выполнения, каждый поток внутри какого-нибудь процесса использует общее виртуальное адресное пространство этого процесса (вдобавок ко всем остальным ресурсам, принадлежащим процессу). Таким образом, все потоки в процессе имеют полноправный доступ к виртуальному адресному пространству процесса. Но потоки не могут случайно сослаться на адресное пространство другого процесса, пока этот другой процесс не сделает часть своего закрытого адресного пространства общим разделом памяти1, или пока у одного процесса не будет прав на открытие другого процесса для использования таких функций памяти, касающихся обоих процессов, как "ReadProcessMemory" и "WriteProcessMemory".
Как показано на рисунке, кроме закрытого адресного пространства и одного или нескольких потоков, у каждого процесса есть контекст безопасности и список открытых дескрипторов таких объектов ядра, как файлы, общие разделы памяти или один из объектов синхронизации из разряда мьютексов, событий или семафоров.
Контекст безопасности каждого процесса хранится в объекте, который называется маркером доступа (access token). Маркер доступа процесса содержит идентификацию безопасности и полномочия процесса. По умолчанию потоки не имеют своего собственного маркера доступа, но они могут получить такой маркер, позволяющий отдельным потокам имитировать контекст безопасности другого процесса, включая процессы на удаленной системе Windows, не оказывая при этом никакого влияния на другие потоки процесса.
Дескрипторы виртуального адресного пространства — "virtual address descriptors (VAD)" являются структурами данных, используемых диспетчером памяти для отслеживания виртуальных адресов, используемых процессом.
Windows предоставляет расширение модели процесса, называемое заданием (job). Основная функция объектов заданий заключается в том, чтобы управлять группами процессов как единым целым и осуществлять на них одновременное воздействие. Объект задания позволяет управлять конкретными атрибутами и предоставляет ограничения для процесса или процессов, связанных с заданием.
Он также записывает основную учетную информацию для всех процессов, связанных с заданием, а также для всех процессов, которые были связаны с заданием ранее, но на данный момент уже завершены. Некоторым образом, объект задания компенсирует в Windows отсутствие структурированного дерева процесса, но во многих отношениях он является более мощным средством, чем дерево процесса в UNIX-стиле.