Потоки в windows это

Обновлено: 02.07.2024

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


увеличить изображение
Рис. 2.1. Состояния потока и переходы между ними

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Работа операционной системы Windows основана на работе процессов. В этой статье разберём что такое Windows процессы, их свойства, состояния и другое.

Процессы

Процесс стоит воспринимать как контейнер с набором ресурсов для выполнения программы. То есть запускаем мы программу, для неё выделяется часть ресурсов компьютера и эта программа работает с этими ресурсами.

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

Windows процессы состоят из следующего:

  • Закрытое виртуальное адресное пространство, то есть выделенная для процесса часть оперативной памяти, которая называется виртуальной.
  • Исполняемая программа выполняя свой код, помещает его в виртуальную память.
  • Список открытых дескрипторов. Процесс может открывать или создавать объекты, например файлы или другие процессы. Эти объекты нумеруются, и их номера называют дескрипторами. Ссылаться на объект по дескриптору быстрее, чем по имени.
  • Контекст безопасности. Сюда входит пользователь процесса, группа, привилегии, сеанс и другое.
  • Идентификатор процесса, то есть его уникальный номер.
  • Программный поток (как минимум один или несколько). Чтобы процесс хоть что-то делал, в нем должен существовать программный поток. Если потока нет, значит что-то пошло не так, возможно процесс не смог корректно завершиться, или стартовать.

У процессов есть еще очень много свойств которые вы можете посмотреть в “Диспетчере задач” или “Process Explorer“.

Процесс может быть в различных состояниях:

В Windows существуют процессы трёх типов:

  • Приложения. Процессы запущенных приложений. У таких приложений есть окно на рабочем столе, которое вы можете свернуть, развернуть или закрыть.
  • Фоновые процессы. Такие процессы работают в фоне и не имеют окна. Некоторые процессы приложений становятся фоновыми, когда вы сворачиваете их в трей.
  • Процессы Windows. Процессы самой операционной системы, например “Диспетчер печати” или “Проводник”.

Дерево процессов

В Windows процессы знают только своих родителей, а более древних предков не знают.

Например у нас есть такое дерево процессов:

Если мы завершим дерево процессов “Процесс_1“, то завершатся все процессы. Потому что “Процесс_1” знает про “Процесс_2“, а “Процесс_2” знает про “Процесс_3“.

Если мы вначале завершим “Процесс_2“, а затем завершаем дерево процессов “Процесс_1“, то завершится только “Процесс_1“, так как между “Процесс_1” и “Процесс_3” не останется связи.

Например, запустите командную строку и выполните команду title parrent чтобы изменить заголовок окна и start cmd чтобы запустить второе окно командной строки:

Измените заголовок второго окна на child и из него запустите программу paint:

В окне командной строке child введите команду exit, окно закроется а paint продолжит работать:

После этого на рабочем столе останутся два приложения, командная строка parrent и paint. При этом parrent будет являться как бы дедом для paint.

Запустите “Диспетчер задач”, на вкладке “Процессы” найдите процесс “Обработчик команд Windows”, разверните список и найдите “parrent“. Затем нажмите на нём правой копкой мыши и выберите “Подробно”:

Подробности по процессу parrent

Вы переключитесь на вкладку “Подробно” с выделенным процессом “cmd.exe“. Нажмите правой кнопкой по этому процессу и выберите «Завершить дерево процессов»:

Завершаем дерево процессов в диспетчере задач

Окно командной строки Parrent завершится а Paint останется работать. Так мы убедились что связи между первым процессом и его внуком нет, если у внука нет непосредственного родителя.

Потоки

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

  • два стека: для режима ядра и для пользовательского режима;
  • локальную памятью потока (TLS, Thread-Local Storage);
  • уникальный идентификатор потока (TID, Thread ID).

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

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

Волокна и планирование пользовательского режима

Потоки выполняются на центральном процессоре, а за их переключение отвечает планировщик ядра. В связи с тем что такое переключение это затратная операция. В Windows придумали два механизма для сокращения таких затрат: волокна (fibers) и планирование пользовательского режима (UMS, User Mode Scheduling).

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

Потоки UMS (User Mode Scheduling), доступные только в 64-разрядных версиях Windows, предоставляют все основные преимущества волокон при минимуме их недостатков. Потоки UMS обладают собственным состоянием ядра, поэтому они «видимы» для ядра, что позволяет нескольким потокам UMS совместно использовать процессор и конкурировать за него. Работает это следующим образом:

  • Когда двум и более потокам UMS требуется выполнить работу в пользовательском режиме, они сами могут периодически уступать управление другому потоку в пользовательском режиме, не обращаясь к планировщику. Ядро при этом думает что продолжает работать один поток.
  • Когда потоку UMS все таки нужно обратиться к ядру, он переключается на специально выделенный поток режима ядра.

Задания

Задания Windows (Job) позволяют объединить несколько процессов в одну группу. Затем можно этой группой управлять:

  • устанавливать лимиты (на память или процессорное время) для группы процессов входящих в задание;
  • останавливать, приостанавливать, запускать такую группу процессов.

Посмотреть на задания можно с помощью Process Explorer.

Диспетчер задач

Чаще всего для получения информации о процессе мы используем «Диспетчер задач». Запустить его можно разными способами:

  • комбинацией клавиш Ctrl+Shift+Esc;
  • щелчком правой кнопкой мыши на панели задач и выборе «Диспетчер задач»;
  • нажатием клавиш Ctrl+Alt+Del и выборе «Диспетчер задач»;
  • запуском исполняемого файла C:\Windows\system32\Taskmgr.exe.

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

Краткий режим Диспетчера задач

В полном режиме на вкладке «Процессы» виден список процессов и информация по ним. Чтобы получить больше информации можно нажать правой кнопкой мышки на заголовке и добавить столбцы:

Диспетчер задач - Добавление столбцов с информацией

Чтобы получить еще больше информации можно нажать правой кнопкой мышки на процессе и выбрать «Подробно». При этом вы переключитесь на вкладку «Подробности» и этот процесс выделится.

На вкладке «Подробности» можно получить ещё больше информации о процессе. А также здесь также можно добавить колонки с дополнительной информацией, для этого нужно щелкнуть правой кнопкой мыши по заголовку и нажать «Выбрать столбцы»:

Выбор столбцов с информацией о процессах на вкладке «Подробности»

Process Explorer

Установка и подготовка к работе

Более подробную информацию о процессах и потоках можно получить с помощью программы Process Explorer из пакета Sysinternals. Его нужно скачать и запустить.

Некоторые возможности Process Explorer:

  • информация по правам процесса: кто владелец процесса, у кого есть доступ к нему;
  • выделение разными цветами процессов и потоков, для удобного восприятия информации:
    • процессы служб – розовый;
    • ваши собственные процессы – синий;
    • новые процессы – зелёный;
    • завершенные процессы – красный;
    • число дескрипторов у процесса;
    • активность потоков в процессе;
    • подробную информация о распределении памяти.

    Запустите Process Explorer:

    Process Explorer

    Предупреждение о не настроенных символических именах

    Для начала скачиваем установщик «Пакет SDK для Windows 10».

    Устанавливать все не нужно, достаточно при установки выбрать “Debugging Tools for Windows“:

    Установка SDK для Windows 10

    Для настройки символических имен перейдите в меню Options / Configure / Symbols. Введите путь к библиотеке Dbghelp.dll, которая находится внутри установленного «Пакета SDK для Windows 10» по умолчанию:

    • C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Dbghelp.dll.

    И путь к серверу символической информации:

    Некоторые основные настройки Process Explorer:

    • Смена цветового выделения – Options / Configure Colors.
    • Выбор колонок с информацией о процессах – View / Select Columns.
    • Сортировка процессов – нужно щелкнуть на заголовке столбца Process, при первом щелчке сортировка будет в алфавитном порядке, при втором в обратном порядке, при третьем вернется в вид дерева.
    • Просмотр только своих процессов – View / снять галочку Show Processes from All Users.
    • Настройка времени выделения только что запущенных процессов и завершённых – Options / Difference Highlight Duration / введите количество секунд.
    • Чтобы исследователь процесс подробнее можно дважды щелкнуть на нем и посмотреть информацию на различных вкладках.
    • Открыть нижнюю панель для просмотра открытых дескрипторов или библиотек – Vies / Show Lower Panel.

    Потоки в Process Explorer

    Потоки отдельного процесса можно увидеть в программе Process Explorer. Для этого нужно дважды кликнуть по процессу и в открывшемся окне перейти на вкладку «Threads»:

    Process Explorer (потоки процесса)

    В колонках видна информация по каждому потоку:

    • TID — идентификатор потока.
    • CPU — загрузка процессора.
    • Cycles Delta — общее количество циклов процессора, которое этот процесс использовал с момента последнего обновления работы Process Explorer. Скорость обновления программы можно настроить, указав например 5 минут.
    • Suspend Count — количество приостановок потока.
    • Service — название службы.
    • Start Address — начальный адрес процедуры, который начинает выполнение нового потока. Выводится в формате:«модуль!функция».

    При выделении потока, снизу показана следующую информация:

    • Идентификатор потока.
    • Время начала работы потока.
    • Состояние потока.
    • Время выполнения в режиме ядра и в пользовательском режиме.
    • Счетчик переключения контекста для центрального процессора.
    • Количество циклов процессора.
    • Базовый приоритет.
    • Динамический приоритет (текущий).
    • Приоритет ввода / вывода.
    • Приоритет памяти.
    • Идеальный процессор (предпочтительный процессор).

    Есть также кнопки:

    Задания в Process Explorer

    Process Explorer может выделить процессы, управляемые заданиями. Чтобы включить такое выделение откройте меню «Options» и выберите команду «Configure Colors», далее поставьте галочку «Jobs»:

    Process Explorer — выделение заданий

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

    Process Explorer — вкладка Job

    Запустите командную строку и введите команду:

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

    В новой командной строке запустите блокнот:

    Далее запускаем Process Explorer и находим такое дерево процессов:

    Устройство Windows. Задания, изображение №3

    Как видим, процесс cmd и notepad это процессы связанные с каким-то заданием. Если дважды кликнуть по любому из этих процессов и перейти на вкладку Job, то мы увидим следующее:

    Потоком в Windows называется объект ядра, которому операционная система выделяет процессорное время для выполнения приложения. Каждому потоку принадлежат следующие ресурсы:

    • код исполняемой функции;
    • набор регистров процессора;
    • стек для работы приложения;
    • стек для работы операционной системы;
    • маркер доступа, который содержит информацию для системы безопасности.

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

    В операционных системах Windows различаются потоки двух типов:

    • системные потоки;
    • пользовательские потоки.

    Системные потоки выполняют различные сервисы операционной системы и запускаются ядром операционной системы.

    Пользовательские потоки служат для решения задач пользователя и запускаются приложением.

    В работающем приложении различаются потоки двух типов:

    • рабочие потоки (working threads);
    • потоки интерфейса пользователя (user interface threads).

    Создается поток функцией CreateThread, которая имеет следующий прототип:

    function CreateThread(
    lpThreadAttributes: Pointer; // атрибуты защиты
    dwStackSize: DWORD; // размер стека потока в байтах
    lpStartAddress: TFNThreadStartRoutine; // адрес функции
    lpParameter: Pointer; // адрес параметра
    dwCreationFlags: DWORD; // флаги создания потока
    var lpThreadId: DWORD // идентификатор потока
    ): THandle;

    При успешном завершении функция CreateThread возвращает дескриптор созданного потока и его идентификатор, который является уникальным для всей системы. В противном случае эта функция возвращает значение nil.

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

    Параметр dwStacksize определяет размер стека, который выделяется потоку при запуске. Если этот параметр равен нулю, то потоку выделяется стек, размер которого по умолчанию равен 1 Мбайт. Это наименьший размер стека, который может быть выделен потоку. Если величина параметра dwStacksize меньше значения, заданного по умолчанию, то все равно потоку выделяется стек размером в 1 Мбайт. Операционная система Windows округляет размер стека до одной страницы памяти, который обычно равен 4 Кбайт.

    Параметр lpStartAddress указывает на исполняемую потоком функцию.

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

    Параметр dwCreationFiags определяет, в каком состоянии будет создан поток. Если значение этого параметра равно 0, то функция потока начинает выполняться сразу после создания потока. Если же значение этого параметра равно CREATE_SUSPENDED, то поток создается в подвешенном состоянии. В дальнейшем этот поток можно запустить вызовом функции ResumeThread.

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

    При создании потока его базовый приоритет устанавливается как сумма приоритета процесса, в контексте которого этот поток выполняется, и уровня приоритета потока THREAD_PRIORITY_NORMAL.

    В листинге 1.1 приведен пример программы, которая использует функцию CreateThread для создания потока и демонстрирует способ передачи параметров исполняемой потоком функции.

    Листинг 1.1. Создание потока функцией CreateThread

    Отметим, что в этой программе используется функция WaitForSingleObject, которая ждет завершения потока Add.

    Поток завершается вызовом функции ExitThread, которая имеет следующий прототип:

    procedure ExitThread(
    dwExitCode: DWORD //код завершения потока
    ); stdcall;

    Один поток может завершить другой поток, вызвав функцию TerminateThread, которая имеет следующий прототип:

    function TerminateThread(
    hThread: THandle; //дескриптор потока
    dwExitCode: DWORD; //код завершения потока
    ): BOOL; stdcall;

    В листинге 1.2 приведена программа, которая демонстрирует работу функции TerminateThread.

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

    function SuspendThread(
    hThread: THandle //дескриптор потока
    ): DWORD; stdcall;

    Эта функция увеличивает значение счетчика приостановок на 1 и, при успешном завершении, возвращает текущее значение этого счетчика. В случае неудачи функция SuspendThread возвращает значение, равное -1.

    Отметим, что поток может приостановить также и сам себя. Для этого он должен передать функции SuspendThread свой псевдодескриптор, который можно получить при помощи функции GetCurrentThread.

    Для возобновления исполнения потока используется функция ResumeThread, которая имеет следующий прототип:

    function ResumeThread(
    hThread: THandle //дескриптор потока
    ): DWORD; stdcall;

    Функция ResumeThread уменьшает значение счетчика приостановок на 1 при условии, что это значение было больше нуля. Если полученное значение счетчика приостановок равно 0, то исполнение потока возобновляется, в противном случае поток остается в подвешенном состоянии. Если при вызове функции ResumeThread значение счетчика приостановок было равным 0, то это значит, что поток не находится в подвешенном состоянии. В этом случае функция не выполняет никаких действий. При успешном завершении функция ResumeThread возвращает текущее значение счетчика приостановок, в противном случае — значение -1.

    Поток может задержать свое исполнение вызовом функции Sleep, которая имеет следующий прототип:

    procedure Sleep(
    dwMilliseconds: DWORD //миллисекунды
    ); stdcall;

    Единственный параметр функции Sleep определяет количество миллисекунд, на которые поток, вызвавший эту функцию, приостанавливает свое исполнение. Если значение этого параметра равно 0, то выполнение потока просто прерывается, а затем возобновляется при условии, что нет других потоков, ждущих выделения процессорного времени. Если же значение этого параметра равно INFINITE, тo поток приостанавливает свое исполнение навсегда, что приводит к блокированию работы приложения.

    В листинге 1.3 приведена программа, которая демонстрирует работу функций SuspendThread, ResumeThread и Sleep.

    Иногда потоку требуется знать свой дескриптор, чтобы изменить какие-то свои характеристики. Например, поток может изменить свой приоритет. Для этих целей в Win32 API существует функция GetcurrentThread, которая имеет следующий прототип:

    function GetCurrentThread: THandle; stdcall;

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

    В листинге 1.4 приведен пример программы, которая вызывает функцию GetCurrentThread, а затем выводит на консоль полученный псевдодескриптор.

    Большинство функций Win32 API возвращают код, по которому можно определить, как завершилась функция: успешно или нет. Если функция завершилась неудачей, то код возврата обычно равен false, nil или -1. В этом случае функция Win32 API также устанавливает внутренний код ошибки, который называется кодом последней ошибки (last-error code) и поддерживается отдельно для каждого потока. Чтобы получить код последней ошибки, нужно вызвать функцию GetLastError, которая имеет следующий прототип:

    function GetLastError: DWORD; stdcall;

    Эта функция возвращает код последней ошибки, установленной в потоке. Установить код последней ошибки в потоке можно при помощи функции SetLastError, имеющей следующий прототип:

    procedure SetLastError(
    dwErrCode: DWORD //код ошибки
    ); stdcall;

    В листинге 1.5 приведен пример программы, которая вызывает функцию FormatMessage

    Исходный код скачать. Выполнен на Delphi XE.

    Используемая литература: Александр Побегайло "Системное программироввние в Windows"

    Внутри каждого процесса могут выполняться одна или несколько потоков, и именно поток является базовой единицей выполнения в Windows. Выполнение потоков планируется системой на основе обычных факторов: наличие таких ресурсов, как CPU и физическая память, приоритеты, равнодоступность ресурсов и так далее. Начиная с версии NT4, в Windows поддерживается симметричная многопроцессорная обработка (Symmetric Multiprocessing, SMP), позволяющая распределять выполнение потоков между отдельными процессорами, установленными в системе.

    С точки зрения программиста каждому процессу принадлежат ресурсы, представленные следующими компонентами:

    • Одна или несколько потоков.

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

    • Один или несколько сегментов кода, включая код DLL.

    • Один или несколько сегментов данных, содержащих глобальные переменные.

    • Строки, содержащие информацию об окружении, например, информацию о текущем пути доступа к файлам.

    • Различного рода ресурсы, например, дескрипторы открытых файлов и другие кучи.

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

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

    • Локальные области хранения потока (Thread Local Storage, SLT) — массивы указателей, используя которые каждый поток может создавать собственную уникальную информационную среду.

    • Аргумент в стеке, получаемый от создающего потока, который обычно является уникальным для каждого потока.

    • Структура контекста, поддерживаемая ядром системы и содержащая значения машинных регистров.

    На рис. 6.1 показан процесс с несколькими потоками. Рисунок является схематическим, поэтому на нем не указаны фактические адреса памяти и не соблюдены масштабы.

    В данной главе показано, как работать с процессами, состоящими из единственного потока. О том, как использовать несколько потоков, рассказывается в главе 7.

    Примечание

    Процессы UNIX сопоставимы с процессами Windows, имеющими единственный поток.

    Реализации UNIX недавно пополнились потоками POSIX Pthreads, которые в настоящее время используются почти повсеместно. В [40] потоки не обсуждаются; все рассмотрение основано на процессах.

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

    Рис. 6.1. Процесс и его потоки

    Процессы и потоки

    Процессы и потоки В этой главе представлено описание процессов и потоков в QNX/ Neutrino, диспетчеризации, системы приоритетов, и дано понятие о реальном времени. Вы узнаете о состояниях потоков и алгоритмах диспетчеризации, которые применяются в QNX/ Neutrino, а также изучите

    Процессы и потоки

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

    2. Процессы и потоки

    2. Процессы и потоки При внимательном чтении технической документации [8] и литературы по ОС QNX [1] отчетливо бросается в глаза, что тонкие детали создания и функционирования процессов и потоков описаны крайне поверхностно и на весьма некачественном уровне. Возможно, это

    Потоки

    Потоки Последующие расширения[14] POSIX специфицируют широкий спектр механизмов «легких процессов» — потоков (группа API pthread_*()). Техника потоков вводит новую парадигму программирования вместо уже ставших традиционными UNIX-методов. Это обстоятельство часто недооценивается.

    Процессы, задачи, задания, группы активизации и потоки

    Процессы, задачи, задания, группы активизации и потоки Как уже упоминалось, первоначально в AS/400 было определено три уровня работы. Самый низкий уровень, под MI, — задача. Процесс «живет» на уровне MI и построен на структуре задач SLIC. Поверх модели процессов MI OS/400 в качестве

    10.4 ПОТОКИ

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

    1.2. Процессы, потоки и общий доступ к информации

    1.2. Процессы, потоки и общий доступ к информации В традиционной модели программирования Unix в системе могут одновременно выполняться несколько процессов, каждому из которых выделяется собственное адресное пространство. Это иллюстрирует рис. 1.1. Рис. 1.1. Совместное

    Потоки

    Потоки Хотя концепция процессов в системах Unix используется уже очень давно, возможность использовать несколько потоков внутри одного процесса появилась относительно недавно. Стандарт потоков Posix.1, называемый Pthreads, был принят в 1995 году. С точки зрения взаимодействия

    38. Потоки

    38. Потоки Язык C++ не обладает средствами для ввода/вывода. Ему это и не нужно; подобные средства легко и элегантно можно создать, применяя сам язык. Стандартная библиотека потокового ввода/вывода дает возможность осуществлять гибкий и эффективный с гарантией типа метод

    7.3.1.2. Потоки

    7.3.1.2. Потоки Потоки (streams) сетевого взаимодействия были разработаны Деннисом Ритчи для Unix Version 8 (1985). Их новая реализация называется STREAMS (именно так, в документации все буквы прописные). Впервые она стала доетупной в версии 3.0 System V Unix (1986). Средство STREAMS обеспечивало

    7.3.1.2. Потоки

    7.3.1.2. Потоки Потоки (streams) сетевого взаимодействия были разработаны Деннисом Ритчи для Unix Version 8 (1985). Их новая реализация называется STREAMS (именно так, в документации все буквы прописные). Впервые она стала доступной в версии 3.0 System V Unix (1986). Средство STREAMS обеспечивало

    2.2.1.1 Потоки

    2.2.1.1 Потоки Архитектуру INFORMIX-OnLine DS называют также многопотоковой. Для каждого клиента создается так называемый поток, или нить (thread). Поток - это подзадача, выполняемая в рамках одного из серверных процессов. В некоторых случаях для обслуживания одного клиентского

    8.3 Файлы и Потоки

    8.3 Файлы и Потоки Потоки обычно связаны с файлами. Библиотека потоков содает стандартный поток ввода cin, стандартный поток вывода cout и стандартный поток ошибок cerr. Программист может отрывать другие файлы и создавать для них

    ГЛABA 6 Процессы, потоки и задания

    ГЛABA 6 Процессы, потоки и задания B этой главе мы рассмотрим структуры данных и алгоритмы, связанные с процессами, потоками и заданиями в Microsoft Windows. B первом разделе основное внимание уделяется внутренним структурам данных, из которых состоит процесс. Bo втором разделе

    Читайте также: