Энциклопедия мобильной связи

Преодолевая границы Windows: процессы и потоки. Операционные системы

Добрый день. Сегодня хотелось бы разобрать, что такое потоки в процессоре. Те самые, о функциях и возможностях которых большинство и не догадывается, однако любят хвастаться остальным.

Цель функции заключается в том, что на 1 ядро может одновременно обрабатывать несколько потоков данных. Пока первый поток простаивает, а второй занимается вычислением, запущенное приложение может воспользоваться вакантной логической мощью для своих целей. В результате, прерывания случаются гораздо реже, а вы не ощущаете тормозов и прочих неудобств при работе.

Недостаток технологии заключается в следующем:

  • оба потока обращаются к единой кэш-памяти 2 и 3 уровней;
  • тяжелые вычислительные процессы могут вызвать конфликт в системе.

Если очень грубо, то все кирпичи с одного места на другое можно перенести в одной руке (1 поток), либо в двух (2 потока), но человек при этом один (1 ядро) и устает одинаково при любых условиях, хоть его производительность фактически увеличивается вдвое. Иными словами, мы упираемся в производительность ЦП, а конкретней в его частоту.

Аннотация: Стратегия управления памятью, процессы, потоки и данные.

Процессы

Появление у компьютера операционной системы (ОС) позволило перейти от однопрограммного режима работы к многопрограммному (мультипрограммному) режиму работы. Операционную систему часто называют многозадачной, полагая, что она выполняет одновременно несколько задач. То, что для ОС является задачей, с точки зрения C# программиста является приложением или проектом. В разных операционных системах для одних и тех же или схожих понятий используются разные термины. Далее, говоря об ОС, будем иметь в виду ОС Windows , и будем использовать терминологию, характерную для этой ОС.

Для каждого выполняемого проекта нашего приложения операционная система создает процесс. В каждый момент времени работы компьютера ОС работает с множеством процессов, многие из которых являются служебными. Некоторые из этих процессов, как например, антивирусное приложение , на моем компьютере присутствуют постоянно, будучи запущенными при включении компьютера.

Одна из главных задач ОС состоит в распределении ограниченных ресурсов компьютера между всеми приложениями, претендующими на эти ресурсы. О каких ресурсах идет речь? Основными, конечно же, являются два ресурса - память и время - прежде всего, оперативная память и время процессоров. Экономия этих ресурсов является постоянной заботой программиста. В серьезных приложениях, разрабатывая алгоритм решения, программисту всегда приходится идти на компромисс , поскольку, как правило, эти два ресурса конфликтуют. Выиграешь в памяти, проиграешь во времени работы, пожертвуешь памятью, выиграешь во времени.

При создании новых компьютеров, согласно закону Мура, каждые полтора года эти ресурсы удваиваются. В 1960 году оперативная память компьютера Урал, одного из лучших компьютеров на тот момент, составляла 2К, а быстродействие - 100 операций в секунду. Сегодня современный суперкомпьютер имеет быстродействие , измеряемое петафлопами - 10 15 - тысяча триллионов операций с плавающей точкой. Аналогичным образом возросли и объемы оперативной памяти, примерно сто триллионов байтов. Казалось бы, можно не заботиться об экономии памяти и времени. Но это не так. Сложность появляющихся задач также растет по экспоненте. Считается, что всегда есть задачи, которые хотелось бы решить на компьютере, но мощности компьютеров не хватает для их решения.

По этой причине ОС тщательно заботится о распределении оперативной памяти и времени процессоров между всеми приложениями. Предметом заботы являются и другие ресурсы - устройства доступа к внешней памяти ( доступ к файлам), другие устройства ввода - вывода, вообще все устройства компьютера.

Процесс - владелец ресурсов . Когда ОС создает процесс, то выделяет ему ресурсы. Процесс, несмотря на свое название, не выполняет код приложения, следовательно, время процессора непосредственно процессу не выделяется. Когда говорится, "процессы ядра ОС могут выполняться в привилегированном режиме, выполняя команды компьютера, недоступные другим процессам", то это некоторая условность. Код выполняют потоки. Именно потокам ОС выделяет процессорное время . При создании процесса ОС всегда создает поток , связывая его с процессом. В процессе выполнения потока могут создаваться и другие потоки, связанные с процессом. Подробнее об этом поговорим чуть позже, а сейчас рассмотрим стратегию управления памятью.

Процессы и стратегия управления памятью

Блестящая стратегическая идея в управлении памятью состоит в том, чтобы процессу выделять не реальную оперативную память, а виртуальную, которую уже потом некоторым образом связывать с реальной памятью. Для 32 разрядных компьютеров адресное пространство составляет 2 32 байтов, примерно 4 Гб. Оперативная память компьютера долгие годы была меньше виртуальной, теперь она практически сравнялась по объему. При желании можно приобрести 32-х разрядный ПК с 4 Гб оперативной памяти, хотя это и неэффективно, поскольку только 2 или 3 Гб будут использоваться в качестве оперативной памяти. По этой причине в ближайшие годы предстоит массовый переход на 64-х битную архитектуру, где виртуальная память становится практически неограниченной по нынешним меркам, так что любая реальная оперативная память будет составлять малую толику виртуального пространства.

Ноутбук, на котором я сейчас пишу этот текст, является 64-битным компьютером с оперативной памятью в 6 Гб, с 4-мя физическими ядрами и соответственно с 8-мю логическими процессорами.

Вернемся к 32-х битной архитектуре. Из 4-х Гб виртуальной памяти ОС отводит процессу 2 или 3 Гб виртуальной памяти, оставляя для себя оставшуюся часть пространства. Так что ни один из процессов не обижен, каждый получает виртуальную память одинакового размера. В то же время достаточное пространство отводится самой операционной системе, которая занимает постоянную часть виртуальной памяти, не пересекающееся с памятью, отводимой процессам. Следующая идея состоит в том, что виртуальная и оперативная память рассматривается как состоящая из страниц. Страницы могут быть большими и малыми. У тех и других есть свои преимущества. Малые страницы имеют сравнительно небольшой объем, обычно 4К.

При трансляции приложения - его программный код и необходимые данные размещаются в виртуальной памяти. На одной из виртуальных страниц находится точка входа в приложение - процедура Main, с которой начинается выполнение. Но процессор компьютера не может выполнять код и использовать данные, находящиеся в виртуальной памяти, они должны находиться в реальной оперативной памяти. Поэтому при создании процесса приложение загружается в оперативную память. Это означает, что соответствующие виртуальные страницы отображаются на страницы реальной оперативной памяти. Всякий раз, когда при выполнении требуется очередная виртуальная страница, менеджер операционной системы проверяет, загружен ли ее образ в оперативную память, и если нет, то происходит загрузка с диска (внешней памяти) соответствующей страницы в свободную страницу оперативной памяти. Но оперативная память ограничена по сравнению с виртуальной. Следует помнить, что ОС одновременно выполняет несколько приложений, все они претендуют на оперативную память, так что "пряников на всех может не хватить" - может оказаться, что свободных страниц оперативной памяти нет. Тогда наступает время свопинга - одна из занятых страниц оперативной памяти вытесняется на диск, и новая страница загружается на ее место. Какую страницу вытеснить - это проблема, решаемая операционной системой. У ОС есть свои критерии оценки того, какая из страниц наиболее вероятно не понадобится в ближайшее время. Как правило, эти критерии хорошо работают и свопинг происходит не часто, хотя встречаются "плохие" примеры, когда значительная часть времени уходит на свопинг - обмен страницами между внешней и оперативной памятью. Причина того, что свопинг происходит к счастью не часто, понятна - большую часть времени приложение проводит, выполняя в цикле некоторую часть программы, работая с фиксированным набором данных. В этом случае приложение локально работает с небольшим набором страниц, которые уже находятся в оперативной памяти. По ходу развития алгоритма точки локализации смещаются, используются новые страницы памяти, но изменение точек локализации происходит, как правило, не часто в сравнении с общим временем решения задачи.

Такова типичная схема выделения памяти процессам операционной системы. Более глубокое рассмотрение этого вопроса дается в курсе, посвященном операционным системам. Теперь же следует поговорить о потоках и стратегии управления временем процессоров - еще одним важнейшим ресурсом компьютера.

Потоки и стратегия управления временем процессоров

Процесс - объект, владеющий памятью и другими ресурсами, но не выполняющий код. Поток - динамический объект, он может быть создан в процессе выполнения кода приложения и может быть удален по ходу выполнения. У процесса может быть несколько одновременно существующих потоков, выполняющих различные фрагменты кода. ОС планирует время процессоров между потоками, и для нее не имеет значение, какому процессу принадлежит тот или иной поток. Говоря о потоках в операционной системе, будем рассматривать общую схему, опуская многие детали, основываясь на стратегии распределения процессорного времени, характерной для ОС Windows. Эта стратегия носит название "вытесняющая приоритетная многозадачность". Многозадачность в данном контексте означает, что планировщик ОС, распределяет время процессора между многими потоками, присутствующими в ОС.

Приоритетность означает, что потоки могут иметь разные приоритеты. В этом случае из двух потоков, готовых к выполнению, на выполнение будет выбран тот, у кого больше приоритет. Более того, если в процессе выполнения потока появился готовый к выполнению поток с большим приоритетом, то выполнение текущего потока будет приостановлено, даже если не истек отведенный ему квант времени. Когда на дороге появляется президентский кортеж, то все участники дорожного движения останавливаются и ждут, пока кортеж не проедет. Все потоки распределяются по группам приоритетности, потоки из одной группы могут быть выбраны на выполнение только в том случае, если нет готовых к выполнению потоков в группах с высшей приоритетностью.

Значит ли это, что могут быть "обиженные" приложения с низким приоритетом, до выполнения которых никогда не дойдет очередь? Это не так. ОС старается никого не обидеть. Если некоторое приложение долго не выполнялось, то ОС временно повышает его приоритет, так что и оно начнет выполняться.

Вытесняющая многозадачность характеризует стратегию планирования для потоков с одинаковым приоритетом. Все потоки в одной группе выстраиваются в очередь. Каждому из них в соответствии с очередью отводится на выполнение некоторый квант времени процессора. По истечении этого кванта поток переводится в состояние "готовность" независимо от его желания продолжить работу, и в состояние "выполнение" переводится следующий по очереди поток. Эту стратегию иногда называют "каруселью". Карусель сделала несколько оборотов, остановилась, все выходят, и места занимают следующие желающие прокатиться, ожидающие с нетерпением своей очереди.

На Рис. 2.1 показаны возможные состояния потока и переходы из одного состояния в другое.

После создания потока и должной инициализации поток переходит в состояние "готовность", занимая в своей группе приоритетности место в конце очереди". Планировщик ОС в соответствии с описанной стратегией выбирает поток, переводя его в состояние "выполнение". По истечении отведенного кванта времени поток возвращается в состояние "готовность", становясь в хвост очереди в своей группе приоритетности. Из состояния "выполнение" поток может перейти в другие состояния и до завершения отведенного кванта времени. В состояние "готовность" он может перейти, если появился поток с большим приоритетом. В состояние "завершение" поток переходит, выполнив свою работу, завершив выполнение отведенного ему фрагмента кода. В состояние "ожидание" поток может перейти, если его дальнейшее выполнение возможно только после наступления некоторого события (например, ему требуются данные, а устройство компьютера, выполняющее ввод этих данных, еще не завершило свою работу). Из состояния "ожидание" поток может перейти в состояние "готовность", если наступило событие, ожидаемое потоком. За время жизни потока он многократно проходит цикл {готовность} -> {выполнение} -> {ожидание} -> {готовность}, иногда минуя переход в состояние "ожидания".

Для понимания картины в целом нужно помнить, что весь процесс вычислений на компьютере управляется событиями. Каждый поток во время своего выполнения многократно прерывается, уступая свое место другому потоку. События, приводящие к приостановке выполнения потока, могут быть асинхронными по отношению к его работе, - они могут произойти в любой момент выполнения потока. Такие события называются прерываниями. Синхронные события, связанные с тем, что по тем или иным причинам выполнение потока становится невозможным, называются исключениями или исключительными ситуациями. Типичными примерами исключительных ситуаций являются такие ситуации, как попытка деления целого числа на ноль или попытка чтения записи несуществующего файла.

Прерывания инициируются аппаратурой компьютера, чаще всего таймером и устройствами ввода-вывода. ОС в очень коротком цикле рассматривает все возникшие прерывания и должным образом их обрабатывает. Когда возникает прерывание от таймера, то ОС при его обработке из кванта времени, отводимого выполняемому потоку, вычитает время, равное интервалу таймера. Если отводимое потоку время исчерпано, поток снимается с выполнения, переходя в состояние "готовность". Когда устройство ввода заканчивает выполнение очередного задания, оно инициализирует аппаратное прерывание, свидетельствующее о завершении работы. Обрабатывая это прерывание, ОС может перевести некоторый поток из состояния "ожидания" в состояние "готовности", поскольку выполнена его заявка на ввод данных.

У исключений, связанных с самим потоком, более широкий спектр. Потоку, например, может понадобиться ввод внешних данных. Поток не может непосредственно обратиться к устройству ввода. Устройство одно, а потоков много. Поэтому поток вызывает соответствующий системный сервис. С точки зрения ядра ОС возникло исключение. При его обработке поток переводится в режим "ожидания", и начинает работать поток, содержащий соответствующий сервис, который анализирует загруженность устройства, формирует новую заявку для устройства, ставя ее в очередь.

Причина исключения может быть как аппаратной, так и программной. Деление на ноль, это, конечно же, программная ошибка. Исключения, связанные с тем, что не прочитаны требуемые внешние данные, могут быть связаны как со сбоем аппаратуры, так и с неверно заданными адресами в программе. Если письмо не доставлено, то виноватой может быть почтовая служба, а возможно вы послали письмо "на деревню дедушке".

Поток может сам инициировать исключение, уведомляя, например, ОС о том, что он "засыпает" на некоторое фиксированное время. Обрабатывая это прерывание, ОС переводит поток в состояние "ожидание". При обработке одного из очередных прерываний по таймеру, когда завершается время "сна", указанное потоком, поток переводится из состояния "ожидание" в состояние "готовность". Поток может перейти в состояние "ожидание" и по другим причинам, возникающим в ходе выполнения программного кода, например, ожидая завершения работы другого потока. Примеры того, как всем этим может управлять С# программист, будут рассмотрены позднее.

Современные компьютеры, настольные и портативные имеют несколько процессоров. Практически все продающиеся сегодня компьютеры, предназначенные для индивидуального использования, имеют от двух до четырех ядер. Это позволяет организовать параллельное выполнение фрагментов кода в одном приложении, ускоряя его работу. Для этого в приложении создаются несколько потоков, параллельно работающих, каждый в отдельном ядре процессора. Иногда удается при N ядрах примерно в N раз уменьшить общее время работы приложения. Но, конечно, это возможно не для всякого приложения, а если и возможно, то требует усилий со стороны программиста. Многопоточный параллельный алгоритм сложнее однопоточного последовательного алгоритма. Сложнее становится и отладка. Нужны ли программисту дополнительные сложности? Хотим мы того или нет, но параллельное программирование становится одним из важнейших направлений развития современного программирования. Современные суперкомпьютеры имеют сотни тысяч процессоров. Высокопроизводительные вычисления, требующие распараллеливания алгоритмов, становятся реальностью. Использовать многоядерный компьютер только для последовательных алгоритмов неэффективно, - все равно, что использовать телескоп в качестве лупы для чтения убористого текста.

Конечно, ведутся работы по автоматическому распараллеливанию последовательного алгоритма, ориентированного на выполнение одним процессором. Но возможности здесь ограничены. В большинстве случаев самому программисту приходится разрабатывать параллельный алгоритм своей задачи, позволяющий эффективно использовать возможности современных компьютеров. Новая техника со многими процессорами требует новых программ со многими потоками, новых программ для кластеров и суперкомпьютеров.

Процессы, потоки и данные

Операционная система работает с процессами и потоками и ей необходимо хранить информацию об этих объектах. Каждый процесс хранит код приложения и данные, создаваемые в процессе выполнения приложения. С данными работает поток, выполняя программный код. Эти данные могут быть локальными для потока, созданы в потоке и используются только одним потоком. Но у процесса может быть несколько потоков, в этом случае существуют данные процесса, глобальные для потока, обеспечивающие взаимодействие между потоками.

Когда потоки процесса работают последовательно, например в случае одного процессора, то особых проблем не возникает, поскольку не возникают конфликты при выполнении операций чтения и записи. Тем не менее, при работе с глобальными данными программисту приходится быть крайне аккуратным, убеждаясь, что изменение данных в одном потоке не вредит работе с этими данными в другом потоке. Сложнее ситуация, когда потоки работают параллельно. В этом случае возможны конфликты, например, два потока одновременно пытаются изменить одни и те же данные. В этом случае большое внимание приходится уделять средствам синхронизации потоков при работе с данными. О синхронизации, гонке данных, блокировках и клинчах вкратце говорилось в первой главе. Примеры появятся в последующих главах.

Еще одна проблема с данными состоит в том, что поток может в любой момент быть прерванным, перейти в состояние "ожидание" или "готовность", а потом вновь продолжить свою работу в прерванной точке. Для поддержки такой возможности ОС использует объект, называемый контекстом потока. Он включает локальные данные потока, счетчик, указывающий на команду, с которой необходимо начать прерванное выполнение, другую служебную информацию, необходимую для корректного продолжения прерванной работы.

Есть еще одна проблема, связанная с данными, используемыми потоком. Дело в том, что команды процессора делятся на две группы - команды, выполняемые в привилегированном режиме, и команды, выполняемые в пользовательском режиме. Команды в привилегированном режиме могут выполнять только системные программы, составляющие ядро операционной системы. Эти системные сервисы могут вызываться потоком по ходу выполнения программного кода. Данные о потоке, используемые ядром ОС, хранятся отдельно от данных, используемых в пользовательском режиме.

В адресном пространстве ОС для каждого процесса в момент его создания выделяется специальный блок памяти, называемый EPROCESS, хранящий системную информацию о процессе. Еще один блок с системной информацией - PEB (Process Environment Block) хранится в адресном пространстве самого процесса. В страницах виртуального адресного пространства процесса хранится код приложения и данные, необходимые для работы. Данные хранятся в памяти, называемой стеком (stack) и кучей (heap). Куча создается в момент создания процесса. У процесса может быть несколько куч. Код приложения может храниться частично в закрытых страницах, частично разделяемых страни

цах памяти. Разделяемые страницы двух или более процессов могут отображаться на одни и те же страницы реальной оперативной памяти. За счет этого несколько процессов могут использовать один и тот же программный код в оперативной памяти. Разные приложения могут использовать одну и ту же библиотеку классов - DLL, расположенную в оперативной памяти без дублирования. Понятно, что это не касается данных, данные у каждого процесса свои. Для хранения данных процесса операционная система выделяет защищенные страницы, так что никакой процесс не может получить доступ к данным другого процесса. Есть исключение из этого правила, когда организуется взаимодействие между процессами, но эту ситуацию мы рассматривать не будем.

В адресном пространстве ОС для каждого потока в момент его создания выделяется специальный блок памяти, называемый TPROCESS, хранящий системную информацию о потоке, а в адресном пространстве процесса создается блок с системной информацией - TEB (Thread Environment Block). Для каждого потока создается контекст потока. Уже говорилось, что в ходе работы процессора компьютера с большой частотой происходит смена потоков - пользовательских и системных. Процессор прекращает выполнять один поток и начинает выполнять другой поток. Процесс переключения называется переключением контекстов. Понятно, что, если в любой момент выполнение потока может быть прервано, а затем продолжено через некоторое время, то контекст потока должен содержать всю информацию, необходимую для продолжения вычислений в точке прерывания. Поэтому контекст потока включает все локальные данные потока, адрес команды в программном коде, с которой продолжится вычисление, состояние всех системных регистров в момент прерывания, состояния всех файлов, с которыми работал поток.

Кроме локальных данных поток работает с данными, общими для приложения в целом. Всем потокам одного процесса, доступны общие данные. При параллельной работе потоков возникает необходимость в синхронизации работы потоков для обеспечения корректной работы с данными. Ответственность за корректную работу потоков лежит на программисте. Дальнейшая часть этой главы и будет посвящена вопросам работы с потоками в программах на C#.

Многоядерностью процессоров в нынешнее время никого не удивишь. Наоборот, все стараются чтобы их компьютер поддерживал как можно больше ядер, а следовательно быстрее работал, и это правильно.
Если касаться именно процессоров, то уже давно на рынке встречаются только два производителя - это Intel и AMD. И если вторые рассказывают про свои 8ми и 10-ядерные процессоры (имея ввиду что их много, а значит они мощнее), то первые имеют по 2 и 4 ядра, но делают акцент на свои потоки (не нужно писать гневных комментариев что ядер бывает и больше т.к. здесь и далее описываются процессоры для домашнего использования).

И если посмотреть на сравнительные графики производительности процессоров, то Вы можете увидеть, что 4-ядерный процессор (не все) от Intel будет обгонять 8-ядерный от AMD. Почему же так? Ведь 4 меньше чем 8, а значит должен быть слабее... Но если копнуть поглубже (не прям до кешей, частотой, шиной и т.д.), то можно увидеть одно интересное слово, которым часто описывают процессоры Intel - поддержка Hyper-threading .

Технология Hyper-threading ("гипертрендинг" в простонародье) была изобретена Intel`ом и используется только в их процессорах (не во всех). Я не буду особо глубоко вдаваться в её подробности, если хотите, то можете почитать про неё на . Данная технология позволяет как бы разделять каждое ядро надвое и в итоге вместо одного физического, мы имеем два логических (или виртуальных) и операционная система Windows думает что установлено два вместо одного.

Как узнать сколько потоков в процессоре?

Если Вы хотите узнать про конкретный процессор, то чаще всего в описании в магазинах указывают поддержку Hyper-threading либо вставляя это словосочетание, либо просто абревеатуру HT. Если же нет такого описания, то всегда можно воспользоваться самой правдивой информацией на официальной странице Intel`а http://ark.intel.com/ru/search/advanced/?s=t&HyperThreading=true
Рекомендую пользоваться только этой информацией ибо она самая точная.

Если же Вы хотите узнать уже находясь в системе и конкретно используются эти самые потоки в Вашей системе, то нет ничего проще.

Запускаете любым удобным способом (проще всего сочетание горячих клавиш Ctrl +Shift +Esc ) находясь в любом месте (хоть читая эту статью) и, если у Вас Windows 7, перейдите во вкладку Быстродействие.


Обратите внимание на верхнюю строку с загрузкой процессора и конкретно на количество "квадратов". Вот как раз сколько их будет - столько и будет всех ядер, включая все потоки. Если точнее здесь отображаются все логические/виртуальные ядра, а потоки как раз они и есть.

Если у Вас Windows 8, 8.1 или 10, то такой вкладки не будет, зато есть Производительность.


Здесь я выделил куда нужно обратить внимание. Кстати, я не зря кликнул по этому графику правой кнопкой мыши, потому что если выбрать пункт Логические процессы, то график изменится и будет похож на тот, который в Windows 7, т.е. будет 8 "квадратиков" и графиками загруженности по каждому ядру.
Если у Вас обратная картина, т.е. отображается не один, а несколько графиков, значит как раз и выбран данный пункт в свойствах самого графика.

Разумеется есть ещё несколько способов того, а в данном случае потоков.

Например можно вызвать свойство системы (сочетание клавиш Win + R и вводим systeminfo ) и увидеть там.

В однозадачной ОС пользователь может запустить одновременно не более одной программы и только после того как она закончит работу можно будет запустить другую. В многозадачной ОС пользователи могут одновременно запускать несколько программ или даже несколько копий одной программы.

В чем разница между программой и процессом? Программа – это статическая последовательность команд, а процесс (process ) – это программа и системные ресурсы, необходимые для ее выполнения. Процесс является субъектом владения ресурсами и единицей работы. ОС выделяет каждому процессу порцию системных ресурсов и гарантирует, что программа каждого процесса будет направляться на исполнение в определенном порядке и своевременно.

ОС содержит блок кода, управляющий созданием и удалением процессов, а также отношениями между ними. Этот код называется структурой процессов (process structure ) и в Windows NT реализован диспетчером процессов (process manager ) .

Его основная задача предоставить набор базовых сервисов процесса, которые подсистемы среды могли бы использовать для эмуляции своих собственных уникальных структур процессов.

В разных ОС процессы реализованы по-разному. Они различаются своим представлением (структурами данных), способами именования и защиты, а также отношениями между собой. Базовые процессы Windows NT имеют ряд характеристик, отличающих их от процессов других ОС:

  • процессы реализованы как объекты, и доступ к ним осуществляется посредством объектных сервисов;
  • в адресном пространстве процесса может исполняться несколько потоков;
  • объект-процесс и объект-поток имеют встроенные возможности синхронизации.

Что такое процесс?

Процесс состоит из:

  • исполняемой программы (код и данные);
  • закрытого адресного пространства (address space ) , т.е. набора адресов виртуальной памяти, который процесс может использовать;
  • системных ресурсов , выделяемых ОС процессу во время выполнения программы (семафоров, файлов и т.д.);
  • по крайней мере, одного потока управления (thread of execution ). Поток – это сущность внутри процесса, которую ядро NT направляет на исполнение. Без него программа процесса не может выполняться.

Адресное пространство

С помощью системы виртуальной памяти (virtual memory) программисты (и создаваемые ими процессы) получают логический образ памяти, который не совпадает с ее физической структурой (см. Рис. 1 Виртуальная и физическая память).

При всяком обращении процесса по виртуальному адресу система виртуальной памяти транслирует этот адрес в физический адрес. Она также предотвращает непосредственный доступ процесса к виртуальной памяти, занятой другими процессами или ОС. Для исполнения кода ОС или доступа к памяти ОС поток должен выполняться в режиме ядра (kernel mode) . Большинство процессов – это процессы пользовательского режима (user mode ).

Поток пользовательского режима получает доступ к ОС, вызывая некоторый системный сервис. Когда поток вызывает сервис, происходит переключение из пользовательского режима в режим ядра. ОС проверяет аргументы, переданные сервису, после чего исполняет сервис. Перед возвратом управления пользовательской программе ОС переключает поток обратно в пользовательский режим.

Системные ресурсы

Кроме закрытого адресного пространства, с каждым процессом связан набор системных ресурсов.

Маркер доступа (Access Token ) присоединяет к процессу ОС. Это объект исполнительной системы, который содержит информацию о правах зарегистрированного в системе пользователя, которого представляет данный процесс. Если процессу требуется получить информацию о своем маркере доступа или изменить некоторые атрибуты маркера, он должен открыть описатель своего объекта-маркера. Подсистема защиты определяет, есть ли у объекта такое право.

Ниже маркера доступа расположен набор структур данных, созданный диспетчером виртуальной памяти для отслеживания виртуальных адресов, используемых процессом.

Таблица объектов показана внизу. Процесс открыл описатели потока, файла и секции совместно используемой памяти. Описание виртуального адресного пространства содержит информацию о виртуальных адресах, занятых стеком потока и объектом-секцией.

Объект-процесс

Каждый процесс в Windows NT представлен блоком процесса , создаваемым исполнительной системой (EPROCESS ). В блоке EPROCESS содержатся атрибуты процесса и указатели на некоторые структуры данных. Так, у каждого процесса есть один или более потоков, представляемых блоками потоков исполнительной системы (ETHREAD ). Блок EPROCESS и связанные с ним структуры данных хранятся в системном пространстве. Исключение составляет только блок переменных окружения процесса (process environment block, PEB ), он находится в адресном пространстве процесса (см. Рис. 3 Блоки переменных окружения процесса (PEB) и потока (TEB)).

В исполнительной системе процессы – это объекты исполнительной системы, создаваемые и уничтожаемые диспетчером объектов. Объект-процесс, как и другие объекты, содержит заголовок, создаваемый и инициализируемый диспетчером объектов. В заголовке хранятся стандартные атрибуты объекта, такие как дескриптор защиты объекта, имя и каталог объектов, в котором хранится имя, если оно есть.

Диспетчер процессов определяет атрибуты, хранящиеся в теле объектов-процессов, а также предоставляет системные сервисы для чтения и изменения этих атрибутов. Атрибуты и сервисы для объектов-процессов показаны на Рис. 4 Блоки процесса исполнительной системы (EPROCESS) и ядра (KPROCESS). Объект процесс исполнительной системы включает объект процесс ядра (содержит указатель на объект процесс ядра). Ядро управляет объектом процесс ядра, а исполнительная система управляет объектом исполнительной системы.

Мы рассматриваем основные атрибуты этих объектов по отдельности, для того чтобы лучше понять какие задачи решаются ядром, а какие исполнительной системой. При выполнении лабораторных работ эта детализация не существенна и надо будет использовать Win32 API функции для работы с объектом процесс исполнительной системы.

Рассмотрим основные атрибуты:

  • идентификатор процесса – уникальное значение, идентифицирующее процесс в ОС;
  • базовый приоритет — базовый приоритет потоков процесса;
  • привязка к процессорам (процессорное сродство) – набор процессоров, на которых потоки процесса могут исполняться по умолчанию;
  • размеры квот – максимальный объем резидентной и нерезидентной системной памяти, пространства в файле подкачки и процессорного времени, выделяемый пользовательскому процессу;
  • статус завершения – причина завершения процесса.

Некоторые атрибуты объекта-процесса налагают ограничения на потоки, исполняемые внутри процесса. Например, на многопроцессорном компьютере процессорное сродство может ограничить исполнение потоков процесса только на заданных процессорах. Аналогично, размеры квот регулируют, сколько памяти, пространства в файле подкачки и процессорного времени могут использовать все потоки процесса вместе.

Базовый приоритет процесса помогает ядру NT регулировать приоритет потоков в системе. Приоритеты потоков изменяются, но всегда остаются в диапазоне базовых приоритетов их процессов.

Большинство сервисов объекта-процесса мы будем использовать при выполнении лабораторных работ. Например, сервис завершения процесса останавливает исполнение всех его потоков, закрывает все открытые описатели объектов и уничтожает виртуальное адресное пространство процесса.

Что такое поток?

Поток – это единица исполнения, отдельный счетчик команд или подлежащая планированию сущность внутри процесса.

В то время как процесс – это логическое представление работы, которую должна выполнить ОС, поток отображает одну из, возможно, многих необходимых подзадач. Предположим, что пользователь запустил приложение для работы с базой данных. ОС представляет этот вызов приложения как один процесс. Пусть теперь пользователь запросил генерацию отчета по данным из базы и сохранение этого отчета в файле. Пока идет выполнение этой длительной операции, пользователь ввел новый запрос к базе данных. ОС представляет каждый из запросов – генерацию отчета и новый запрос к базе – как отдельные потоки внутри процесса приложения для работы с базой данных. Эти потоки могут выполняться процессором независимо друг от друга, т.е. обе операции можно выполнять в одно и то же время (параллельно).

Основные составляющие потока в исполнительной системе NT:

  • Уникальный идентификатор, называемый идентификатором клиента
  • Содержимое набора регистров, отражающее состояние процессора
  • Два стека: один используется потоком при работе в пользовательском режиме, а другой — в режиме ядра
  • Собственная область памяти, предназначенная для использования подсистемами, библиотеками периода выполнения и динамически подключаемыми библиотеками (DLL).

Регистры, стек, и собственная область памяти называются контекстом (context) потока. Фактически данные, составляющие контекст потока, определяются типом процессора.

Поток находится в адресном пространстве процесса, используя его для хранения данных во время выполнения. Если в одном процессе существует несколько потоков, то они совместно используют адресное пространство и все ресурсы, включая маркер доступа, базовый приоритет и описатели объектов из таблицы объектов процесса. Ядро NT направляет потоки на исполнение некоторому процессору. Таким образом, каждый процесс NT должен иметь, по меньшей мере, один поток.

Многозадачность и многопроцессорная обработка

ОС вытесняющей многозадачностью должна использовать тот или иной алгоритм, позволяющий ей распределять процессорное время между потоками. Каждые 20 мс Windows просматривает все существующие объекты потоки и отмечает те из них, которые могут получить процессорное время. Далее она выбирает один из таких объектов и загружает в регистры процессора значение его контекста. Эта операция называется переключением контекста (context switching). Поток выполняет код и манипулирует данными в адресном пространстве своего процесса. Примерно через 20 мс Windows сохранит значения регистров процессора в контексте потока и приостановит его выполнение. Далее система просмотрит остальные объекты потоки, подлежащие выполнению, выберет один из них, загрузит его контекст в регистры процессора, и все повторится. Этот цикл операций – выбор потока, загрузка его контекста, выполнение и сохранение контекста – начинается с момента запуска системы и продолжается до ее выключения (см. Рис. 5 Состояния потоков).

Система планирует выполнение только тех потоков, которые могут получить процессорное время. У некоторых объектов-потоков значение счетчика простоев (suspend count) больше 0, это значит, что соответствующие потоки приостановлены и не получают процессорного времени. Кроме приостановленных, существуют и другие потоки, не участвующие в распределении процессорного времени, — они ожидают каких-либо событий.

Поток получает доступ к процессору на 20 мс, после чего планировщик переключает процессор на выполнение другого потока. Но так происходит, только если у всех потоков один приоритет. На самом деле в системе существуют потоки с разными приоритетами, а это меняет порядок распределения процессорного времени.

Каждому потоку присваивается уровень приоритета – от 0 (самый низкий) до 31 (самый высокий). Решая, какому потоку выделить процессорное время, система сначала рассматривает только потоки с приоритетом 31 и подключает их к процессору по принципу карусели. Если поток с приоритетом 31 не исключен из планирования, он получает квант времени, по истечении которого система проверяет, есть ли еще один такой поток. Если есть, то и он получает свой квант процессорного времени.

Пока в системе имеются планируемые потоки с приоритетом 31, ни один поток с более низким приоритетом процессорного времени не получит. Такая ситуация называется голоданием (starvation). Она наблюдается, когда потоки с более высоким приоритетом так интенсивно используют процессор, что остальным ничего не достается.

Кроме того, потоки с более высоким приоритетом вытесняют потоки с более низким приоритетом. Допустим, процессор исполняет поток с приоритетом 5, и тут система обнаруживает, что поток с более высоким приоритетом готов к выполнению. Тогда система остановит поток с более низким приоритетом – даже если не истек отведенный ему квант процессорного времени – подключит к процессору поток с более высоким приоритетом и выдаст ему полный квант времени.

Процессор может выполнять не более одного потока одновременно. Однако многозадачная (multitasking) ОС дает пользователю возможность исполнять несколько программ, причем создается впечатление, что все они исполняются одновременно. Это достигается следующим образом:

  • поток исполняется до тех пор, пока его исполнение не будет прервано или ему не придется ждать освобождения некоторого ресурса;
  • cохраняется контекст потока;
  • загружается контекст другого потока;

этот цикл повторяется до тех пор, пока есть потоки, ожидающие выполнения.

Переключение процессора с исполнения одного потока на исполнение другого потока называется переключением контекста (context switching). В Windows NT оно осуществляется ядром.

Многозадачность увеличивает объем работы, выполняемой системой, потому что большинство потоков не могут исполняться непрерывно. Периодически поток прекращает выполнение и ждет пока другой поток, например, освободит ресурс необходимый первому. Благодаря многозадачности, пока один поток ожидает, может выполняться другой поток, и время процессора не расходуется впустую.

Вытесняющая многозадачность (preemptive multitasking) – это разновидность многозадачности, при которой ОС не ждет, пока поток добровольно предоставит процессор другим потокам. Вместо этого ОС прерывает поток, после того как он выполнялся в течение заранее заданного периода времени, так называемого кванта времени (time quantum), или когда готов к выполнению поток с большим приоритетом. Вытеснение предотвращает монополизацию процессора одним потоком и предоставляет другим потокам их долю процессорного времени. Windows NT – это система с вытесняющей многозадачностью. В невытесняющих системах, поток должен был добровольно передавать управление процессором. Плохие программы могут захватить процессор и нарушить работу других приложений или всей системы.



Понравилась статья? Поделитесь с друзьями!
Была ли эта статья полезной?
Да
Нет
Спасибо, за Ваш отзыв!
Что-то пошло не так и Ваш голос не был учтен.
Спасибо. Ваше сообщение отправлено
Нашли в тексте ошибку?
Выделите её, нажмите Ctrl + Enter и мы всё исправим!