Процессы и потоки. Что такое потоки в процессоре

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

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

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

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

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

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

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

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

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

Существует три основных состояния процесса: "готов", "выполняется", "блокирован".

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

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

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

Виртуальное адресное пространство процесса – это совокупность адресов, которыми может манипулировать программный модуль процесса.

Операционная система отображает виртуальное адресное пространство процесса на отведенную процессу физическую память.

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

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

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

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

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

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

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

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

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

Мультипрограммирование более эффективно на уровне потоков, а не процессов. Каждый поток имеет собственный счетчик команд и стек. Задача, оформленная в виде нескольких потоков в рамках одного процесса, может быть выполнена быстрее за счет псевдопа- раллельного (или параллельного в мультипроцессорной системе) выполнения ее отдельных частей. Особенно эффективно можно использовать многопоточность для выполнения распределенных приложений, например многопоточный сервер может параллельно выполнять запросы сразу нескольких клиентов.

Использование потоков связано не только со стремлением повысить производительность системы за счет параллельных вычислений, но и с целью создания более читабельных, логичных программ. Введение нескольких потоков выполнения упрощает программирование. Например, в задачах типа "писатель-читатель" один поток выполняет запись в буфер, а другой считывает записи из него. Поскольку они разделяют общий буфер, не стоит их делать отдельными процессами. Другой пример использования потоков – управление сигналами, такими как прерывание с клавиатуры (Del или Break). Вместо обработки сигнала прерывания один поток назначается для постоянного ожидания поступления сигналов. Таким образом, использование потоков может сократить необходимость в прерываниях пользовательского уровня. В этих примерах не столь важно параллельное выполнение, сколь ясность программы.

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

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

Примерами описателей процесса являются блок управления задачей (Task Control Block – ТСВ) в OS/360, управляющий блок процесса (Process Control Block – РСВ) в OS/2, дескриптор процесса в UNIX, объект-процесс (object-process) в Windows NT.

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

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

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

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

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

Планирование процессов включает в себя решение следующих задач:

■ определение момента времени для смены выполняемого процесса;

■ выбор процесса на выполнение из очереди готовых процессов;

■ переключение контекстов "старого" и "нового" процессов.

Первые две задачи решаются программными средствами, а последняя – в значительной степени аппаратно.

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

В соответствии с алгоритмами, основанными на квантовании, смена активного процесса происходит, если:

■ процесс завершился и покинул систему;

■ произошла ошибка;

■ процесс перешел в состояние "ожидание";

■ исчерпан квант процессорного времени, отведенный данному процессу.

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

Кванты, выделяемые процессам, могут быть одинаковыми для всех процессов или различными. Кванты, выделяемые одному процессу, могут быть фиксированной величины или изменяться в разные периоды жизни процесса. Процессы, которые не полностью использовали выделенный им квант (например, из-за ухода на выполнение операций ввода/вывода), могут получить или не получить компенсацию в виде привилегий при последующем обслуживании. По-разному может быть организована очередь готовых процессов: циклически, по правилу "первый пришел – первый обслужился" (FIFO) или по правилу "последний пришел – первый обслужился" (LIFO).

В алгоритмах, основанных на приоритетах, используется понятие "приоритет" процесса.

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

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

Существует две разновидности приоритетных алгоритмов: алгоритмы, использующие относительные приоритеты, и алгоритмы, использующие абсолютные приоритеты.

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

Во многих ОС алгоритмы планирования построены с использованием как квантования, так и приоритетов. Например, в основе планирования лежит квантование, но величина кванта и (или) порядок выбора процесса из очереди готовых определяется приоритетами процессов.

Существует два основных типа процедур планирования процессов: вытесняющие (preemptive) и невытесняющие (non-preemptive).

Невытесняющая многозадачность (Non-preemptive multitasking) – это способ планирования процессов, при котором активный процесс выполняется до тех пор, пока он сам, по собственной инициативе, не отдаст управление планировщику ОС, для того чтобы тот выбрал из очереди другой, готовый к выполнению процесс.

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

Понятия "preemptive" и "nοn-preemptive" иногда отождествляют с понятиями приоритетных и бесприоритетных дисциплин, что совершенно неверно, а также с понятиями абсолютных и относительных приоритетов, что неверно отчасти. Вытесняющая и невытесняющая многозадачность – более широкие понятия, чем типы приоритетности. Приоритеты задач могут как использоваться, так и не использоваться и при вытесняющих, и при невытесняющих способах планирования. Так, в случае использования приоритетов дисциплина относительных приоритетов может быть отнесена к классу систем с невытесняющей многозадачностью, а дисциплина абсолютных приоритетов – к классу систем с вытесняющей многозадачностью. Бесприоритетная дисциплина планирования, основанная на выделении равных квантов времени для всех задач, относится к вытесняющим алгоритмам.

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

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

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

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

Однако почти во всех современных ОС, ориентированных на высокопроизводительное выполнение приложений (UNIX, Windows NT, OS/2, VAX/VMS), реализована вытесняющая многозадачность. В последнее время дошла очередь и до ОС класса настольных систем. Возможно, в связи с этим вытесняющую многозадачность часто называют истинной.

4.1 Процессы

4.1.1 Понятие процесса

Процесс (задача) - программа, находящаяся в режиме выполнения.

С каждым процессом связывается его адресное пространство, из которого он может читать и в которое он может писать данные.

Адресное пространство содержит:

    саму программу

    данные к программе

    стек программы

С каждым процессом связывается набор регистров, например:

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

    указатель стека

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

Некоторые поля таблицы:

Управление процессом

Управление памятью

Управление файлами

Регистры

Счетчик команд

Указатель стека

Состояние процесса

Приоритет

Параметры планирования

Идентификатор процесса

Родительский процесс

Группа процесса

Время начала процесса

Использованное процессорное время

Указатель на текстовый сегмент

Указатель на сегмент данных

Указатель на сегмент стека

Корневой каталог

Рабочий каталог

Дескрипторы файла

Идентификатор пользователя

Идентификатор группы

4.1.2 Модель процесса

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

Рассмотрим схему с четырьмя работающими программами.

В каждый момент времени активен только один процесс

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

4.1.3 Создание процесса

Три основных события, приводящие к созданию процессов (вызов fork или CreateProcess ):

    Работающий процесс подает системный вызов на создание процесса

    Запрос пользователя на создание процесса

Во всех случаях, активный текущий процесс посылает системный вызов на создание нового процесса.

В UNIX каждому процессу присваивается идентификатор процесса (PID - Process IDentifier)

4.1.4 Завершение процесса

Четыре события, приводящие к остановке процесса (вызов exit или ExitProcess ):

    Плановое завершение (окончание выполнения)

    Плановый выход по известной ошибке (например, отсутствие файла)

    Выход по неисправимой ошибке (ошибка в программе)

    Уничтожение другим процессом

Таким образом, приостановленный процесс состоит из собственного адресного пространства, обычно называемого образом памяти (core image ), и компонентов таблицы процессов (в числе компонентов и его регистры).

4.1.5 Иерархия процессов

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

В таком случае в UNIX существует и прародитель всех процессов - процесс init .

Дерево процессов для систем UNIX

4.1.6 Состояние процессов

Три состояния процесса:

    Выполнение (занимает процессор)

    Готовность (процесс временно приостановлен, чтобы позволить выполняться другому процессу)

    Ожидание (процесс не может быть запущен по своим внутренним причинам, например, ожидая операции ввода/вывода)

Возможные переходы между состояниями.

1. Процесс блокируется, ожидая входных данных

2. Планировщик выбирает другой процесс

3. Планировщик выбирает этот процесс

4. Поступили входные данные

Переходы 2 и 3 вызываются планировщиком процессов операционной системы, так что сами процессы даже не знают о этих переходах. С точки зрения самих процессов есть два состояния выполнения и ожидания.

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

4.2 Потоки (нити, облегченный процесс)

4.2.1 Понятие потока

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

4.2.2 Модель потока

С каждым потоком связывается:

    Счетчик выполнения команд

    Регистры для текущих переменных

    Состояние

Потоки делят между собой элементы своего процесса:

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

    Глобальные переменные

    Открытые файлы

  • Семафоры

    Статистическую информацию.

В остальном модель идентична модели процессов.

В POSIX и Windows есть поддержка потоков на уровне ядра.

4.2.3 Преимущества использования потоков

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

    Быстрота создания потока, по сравнению с процессом, примерно в 100 раз.

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

4.2.4 Реализация потоков в пространстве пользователя, ядра и смешанное

B - потоки в пространстве ядра

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

Преимущества случая А :

    Такую многопоточность можно реализовать на ядре не поддерживающим многопоточность

    Более быстрое переключение, создание и завершение потоков

    Процесс может иметь собственный алгоритм планирования.

Недостатки случая А :

    Отсутствие прерывания по таймеру внутри одного процесса

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

    Сложность реализации

В этой статье я попытаюсь описать терминологию, используемую для описания систем, способных исполнять несколько программ параллельно, то есть многоядерных, многопроцессорных, многопоточных. Разные виды параллелизма в ЦПУ IA-32 появлялись в разное время и в несколько непоследовательном порядке. Во всём этом довольно легко запутаться, особенно учитывая, что операционные системы заботливо прячут детали от не слишком искушённых прикладных программ.

Используемая далее терминология используется в документации процессорам Intel. Другие архитектуры могут иметь другие названия для похожих понятий. Там, где они мне известны, я буду их упоминать. Цель статьи - показать, что при всём многообразии возможных конфигураций многопроцессорных, многоядерных и многопоточных систем для программ, исполняющихся на них, создаются возможности как для абстракции (игнорирования различий), так и для учёта специфики (возможность программно узнать конфигурацию). Предупреждение о знаках ®, ™, © в статье Мой комментарий объясняет, почему сотрудники компаний должны в публичных коммуникациях использовать знаки авторского права. В этой статье их пришлось использовать довольно часто. Конечно же, самый древний, чаще всего используемый и неоднозначный термин - это «процессор». В современном мире процессор - это то (package), что мы покупаем в красивой Retail коробке или не очень красивом OEM-пакетике. Неделимая сущность, вставляемая в разъём (socket) на материнской плате. Даже если никакого разъёма нет и снять его нельзя, то есть если он намертво припаян, это один чип. Мобильные системы (телефоны, планшеты, ноутбуки) и большинство десктопов имеют один процессор. Рабочие станции и сервера иногда могут похвастаться двумя или больше процессорами на одной материнской плате.

Поддержка нескольких центральных процессоров в одной системе требует многочисленных изменений в её дизайне. Как минимум, необходимо обеспечить их физическое подключение (предусмотреть несколько сокетов на материнской плате), решить вопросы идентификации процессоров (см. далее в этой статье, а также мою предыдущую заметку), согласования доступов к памяти и доставки прерываний (контроллер прерываний должен уметь маршрутизировать прерывания на несколько процессоров) и, конечно же, поддержки со стороны операционной системы. Я, к сожалению, не смог найти документального упоминания момента создания первой многопроцессорной системы на процессорах Intel, однако Википедия утверждает, что Sequent Computer Systems поставляла их уже в 1987 году, используя процессоры Intel 80386. Широко распространённой поддержка же нескольких чипов в одной системе становится доступной, начиная с Intel® Pentium.

Если процессоров несколько, то каждый из них имеет собственный разъём на плате. У каждого из них при этом имеются полные независимые копии всех ресурсов, таких как регистры, исполняющие устройства, кэши. Делят они общую память - RAM. Память может подключаться к ним различными и довольно нетривиальными способами, но это отдельная история, выходящая за рамки этой статьи. Важно то, что при любом раскладе для исполняемых программ должна создаваться иллюзия однородной общей памяти, доступной со всех входящих в систему процессоров.
К взлёту готов! Intel® Desktop Board D5400XS Исторически многоядерность в Intel IA-32 появилась позже Intel® HyperThreading, однако в логической иерархии она идёт следующей.

Казалось бы, если в системе больше процессоров, то выше её производительность (на задачах, способных задействовать все ресурсы). Однако, если стоимость коммуникаций между ними слишком велика, то весь выигрыш от параллелизма убивается длительными задержками на передачу общих данных. Именно это наблюдается в многопроцессорных системах - как физически, так и логически они находятся очень далеко друг от друга. Для эффективной коммуникации в таких условиях приходится придумывать специализированные шины, такие как Intel® QuickPath Interconnect. Энергопотребление, размеры и цена конечного решения, конечно, от всего этого не понижаются. На помощь должна прийти высокая интеграция компонент - схемы, исполняющие части параллельной программы, надо подтащить поближе друг к другу, желательно на один кристалл. Другими словами, в одном процессоре следует организовать несколько ядер, во всём идентичных друг другу, но работающих независимо.

Первые многоядерные процессоры IA-32 от Intel были представлены в 2005 году. С тех пор среднее число ядер в серверных, десктопных, а ныне и мобильных платформах неуклонно растёт. В отличие от двух одноядерных процессоров в одной системе, разделяющих только память, два ядра могут иметь также общие кэши и другие ресурсы, отвечающие за взаимодействие с памятью. Чаще всего кэши первого уровня остаются приватными (у каждого ядра свой), тогда как второй и третий уровень может быть как общим, так и раздельным. Такая организация системы позволяет сократить задержки доставки данных между соседними ядрами, особенно если они работают над общей задачей.
Микроснимок четырёхядерного процессора Intel с кодовым именем Nehalem. Выделены отдельные ядра, общий кэш третьего уровня, а также линки QPI к другим процессорам и общий контроллер памяти. До примерно 2002 года единственный способ получить систему IA-32, способную параллельно исполнять две или более программы, состоял в использовании именно многопроцессорных систем. В Intel® Pentium® 4, а также линейке Xeon с кодовым именем Foster (Netburst) была представлена новая технология - гипертреды или гиперпотоки, - Intel® HyperThreading (далее HT). Ничто не ново под луной. HT - это частный случай того, что в литературе именуется одновременной многопоточностью (simultaneous multithreading, SMT). В отличие от «настоящих» ядер, являющихся полными и независимыми копиями, в случае HT в одном процессоре дублируется лишь часть внутренних узлов, в первую очередь отвечающих за хранение архитектурного состояния - регистры. Исполнительные же узлы, ответственные за организацию и обработку данных, остаются в единственном числе, и в любой момент времени используются максимум одним из потоков. Как и ядра, гиперпотоки делят между собой кэши, однако начиная с какого уровня - это зависит от конкретной системы.

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

В каких случаях наличие «нечестной» многоядерности в виде HT оправдано? Если один поток приложения не в состоянии загрузить все исполняющие узлы внутри ядра, то их можно «одолжить» другому потоку. Это типично для приложений, имеющих «узкое место» не в вычислениях, а при доступе к данным, то есть часто генерирующих промахи кэша и вынужденных ожидать доставку данных из памяти. В это время ядро без HT будет вынуждено простаивать. Наличие же HT позволяет быстро переключить свободные исполняющие узлы к другому архитектурному состоянию (т.к. оно как раз дублируется) и исполнять его инструкции. Это - частный случай приёма под названием latency hiding, когда одна длительная операция, в течение которой полезные ресурсы простаивают, маскируется параллельным выполнением других задач. Если приложение уже имеет высокую степень утилизации ресурсов ядра, наличие гиперпотоков не позволит получить ускорение - здесь нужны «честные» ядра. Типичные сценарии работы десктопных и серверных приложений, рассчитанных на машинные архитектуры общего назначения, имеют потенциал к параллелизму, реализуемому с помощью HT. Однако этот потенциал быстро «расходуется». Возможно, по этой причине почти на всех процессорах IA-32 число аппаратных гиперпотоков не превышает двух. На типичных сценариях выигрыш от использования трёх и более гиперпотоков был бы невелик, а вот проигрыш в размере кристалла, его энергопотреблении и стоимости значителен.

Другая ситуация наблюдается на типичных задачах, выполняемых на видеоускорителях. Поэтому для этих архитектур характерно использование техники SMT с бóльшим числом потоков. Так как сопроцессоры Intel® Xeon Phi (представленные в 2010 году) идеологически и генеалогически довольно близки к видеокартам, на них может быть четыре гиперпотока на каждом ядре - уникальная для IA-32 конфигурация.

Из трёх описанных «уровней» параллелизма (процессоры, ядра, гиперпотоки) в конкретной системе могут отсутствовать некоторые или даже все. На это влияют настройки BIOS (многоядерность и многопоточность отключаются независимо), особенности микроархитектуры (например, HT отсутствовал в Intel® Core™ Duo, но был возвращён с выпуском Nehalem) и события при работе системы (многопроцессорные сервера могут выключать отказавшие процессоры в случае обнаружения неисправностей и продолжать «лететь» на оставшихся). Каким образом этот многоуровневый зоопарк параллелизма виден операционной системе и, в конечном счёте, прикладным приложениям?

Далее для удобства обозначим количества процессоров, ядер и потоков в некоторой системе тройкой (x, y, z), где x - это число процессоров, y - число ядер в каждом процессоре, а z - число гиперпотоков в каждом ядре. Далее я буду называть эту тройку топологией - устоявшийся термин, мало что имеющий с разделом математики. Произведение p = xyz определяет число сущностей, именуемых логическими процессорами системы. Оно определяет полное число независимых контекстов прикладных процессов в системе с общей памятью, исполняющихся параллельно, которые операционная система вынуждена учитывать. Я говорю «вынуждена», потому что она не может управлять порядком исполнения двух процессов, находящихся на различных логических процессорах. Это относится в том числе к гиперпотокам: хотя они и работают «последовательно» на одном ядре, конкретный порядок диктуется аппаратурой и недоступен для наблюдения или управления программам.

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

Windows Task Manager показывает 8 логических процессоров; но сколько это в процессорах, ядрах и гиперпотоках?

Linux top показывает 4 логических процессора. Это довольно удобно для создателей прикладных приложений - им не приходится иметь дело с зачастую несущественными для них особенностями аппаратуры. Конечно, абстрагирование топологии в единственное число логических процессоров в ряде случаев создаёт достаточно оснований для путаницы и недоразумений (в жарких Интернет-спорах). Вычислительные приложения, желающие выжать из железа максимум производительности, требуют детального контроля над тем, где будут размещены их потоки: поближе друг к другу на соседних гиперпотоках или же наоборот, подальше на разных процессорах. Скорость коммуникаций между логическими процессорами в составе одного ядра или процессора значительно выше, чем скорость передачи данных между процессорами. Возможность неоднородности в организации оперативной памяти также усложняет картину. Информация о топологии системы в целом, а также положении каждого логического процессора в IA-32 доступна с помощью инструкции CPUID. С момента появления первых многопроцессорных систем схема идентификации логических процессоров несколько раз расширялась. К настоящему моменту её части содержатся в листах 1, 4 и 11 CPUID. Какой из листов следует смотреть, можно определить из следующей блок-схемы, взятой из статьи :
Я не буду здесь утомлять всеми подробностями отдельных частей этого алгоритма. Если возникнет интерес, то этому можно посвятить следующую часть этой статьи. Отошлю интересующегося читателя к , в которой этот вопрос разбирается максимально подробно. Здесь же я сначала кратко опишу, что такое APIC и как он связан с топологией. Затем рассмотрим работу с листом 0xB (одиннадцать в десятичном счислении), который на настоящий момент является последним словом в «апикостроении». Local APIC (advanced programmable interrupt controller) - это устройство (ныне входящее в состав процессора), отвечающее за работу с прерываниями, приходящими к конкретному логическому процессору. Свой собственный APIC есть у каждого логического процессора. И каждый из них в системе должен иметь уникальное значение APIC ID. Это число используется контроллерами прерываний для адресации при доставке сообщений, а всеми остальными (например, операционной системой) - для идентификации логических процессоров. Спецификация на этот контроллер прерываний эволюционировала, пройдя от микросхемы Intel 8259 PIC через Dual PIC, APIC и xAPIC к x2APIC. В настоящий момент ширина числа, хранящегося в APIC ID, достигла полных 32 бит, хотя в прошлом оно было ограничено 16, а ещё раньше - только 8 битами. Нынче остатки старых дней раскиданы по всему CPUID, однако в CPUID.0xB.EDX возвращаются все 32 бита APIC ID. На каждом логическом процессоре, независимо исполняющем инструкцию CPUID, возвращаться будет своё значение. Значение APIC ID само по себе ничего не говорит о топологии. Чтобы узнать, какие два логических процессора находятся внутри одного физического (т.е. являются «братьями» гипертредами), какие два - внутри одного процессора, а какие оказались и вовсе в разных процессорах, надо сравнить их значения APIC ID. В зависимости от степени родства некоторые их биты будут совпадать. Эта информация содержится в подлистьях CPUID.0xB, которые кодируются с помощью операнда в ECX. Каждый из них описывает положение битового поля одного из уровней топологии в EAX (точнее, число бит, которые нужно сдвинуть в APIC ID вправо, чтобы убрать нижние уровни топологии), а также тип этого уровня - гиперпоток, ядро или процессор, - в ECX.

У логических процессоров, находящихся внутри одного ядра, будут совпадать все биты APIC ID, кроме принадлежащих полю SMT. Для логических процессоров, находящихся в одном процессоре, - все биты, кроме полей Core и SMT. Поскольку число подлистов у CPUID.0xB может расти, данная схема позволит поддержать описание топологий и с бóльшим числом уровней, если в будущем возникнет необходимость. Более того, можно будет ввести промежуточные уровни между уже существующими. Важное следствие из организации данной схемы заключается в том, что в наборе всех APIC ID всех логических процессоров системы могут быть «дыры», т.е. они не будут идти последовательно. Например, во многоядерном процессоре с выключенным HT все APIC ID могут оказаться чётными, так как младший бит, отвечающий за кодирование номера гиперпотока, будет всегда нулевым. Отмечу, что CPUID.0xB - не единственный источник информации о логических процессорах, доступный операционной системе. Список всех процессоров, доступный ей, вместе с их значениями APIC ID, кодируется в таблице MADT ACPI . Операционные системы предоставляют информацию о топологии логических процессоров приложениям с помощью своих собственных интерфейсов.

В Linux информация о топологии содержится в псевдофайле /proc/cpuinfo, а также выводе команды dmidecode. В примере ниже я фильтрую содержимое cpuinfo на некоторой четырёхядерной системе без HT, оставляя только записи, относящиеся к топологии:

Скрытый текст :~$ cat /proc/cpuinfo |grep "processor\|physical\ id\|siblings\|core\|cores\|apicid" processor: 0 physical id: 0 siblings: 4 core id: 0 cpu cores: 2 apicid: 0 initial apicid: 0 processor: 1 physical id: 0 siblings: 4 core id: 0 cpu cores: 2 apicid: 1 initial apicid: 1 processor: 2 physical id: 0 siblings: 4 core id: 1 cpu cores: 2 apicid: 2 initial apicid: 2 processor: 3 physical id: 0 siblings: 4 core id: 1 cpu cores: 2 apicid: 3 initial apicid: 3 В FreeBSD топология сообщается через механизм sysctl в переменной kern.sched.topology_spec в виде XML:Скрытый текст :~$ sysctl kern.sched.topology_spec kern.sched.topology_spec: 0, 1, 2, 3, 4, 5, 6, 7 0, 1, 2, 3, 4, 5, 6, 7 0, 1 THREAD group SMT group 2, 3 THREAD group SMT group 4, 5 THREAD group SMT group 6, 7 THREAD group SMT group В MS Windows 8 сведения о топологии можно увидеть в диспетчере задач Task Manager.Скрытый текст

Также их предоставляет консольная утилита Sysinternals Coreinfo и API вызов GetLogicalProcessorInformation.

Проиллюстрирую ещё раз отношения между понятиями «процессор», «ядро», «гиперпоток» и «логический процессор» на нескольких примерах.


В этот раздел я вынес некоторые курьёзы, возникающие из-за многоуровневой организации логических процессоров. Как я уже упоминал, кэши в процессоре тоже образуют иерархию, и она довольно сильно связано с топологией ядер, однако не определяется ей однозначно. Для определения того, какие кэши для каких логических процессоров общие, а какие нет, используется вывод CPUID.4 и её подлистов. Некоторые программные продукты поставляются числом лицензий, определяемых количеством процессоров в системе, на которой они будут использоваться. Другие - числом ядер в системе. Наконец, для определения числа лицензий число процессоров может умножаться на дробный «core factor», зависящий от типа процессора! Системы виртуализации, способные моделировать многоядерные системы, могут назначить виртуальным процессорам внутри машины произвольную топологию, не совпадающую с конфигурацией реальной аппаратуры. Так, внутри хозяйской системы (1, 2, 2) некоторые известные системы виртуализации по умолчанию выносят все логические процессоры на верхний уровень, т.е. создают конфигурацию (4, 1, 1). В сочетании с особенностями лицензирования, зависящими от топологии, это может порождать забавные эффекты. Спасибо за внимание!

habrahabr.ru

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

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

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

Таким образом, производственные способности просто нивелируются. Это явление получило название bottleneck, что в переводе значит «узкое место» или «узкая шея».

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

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

Само ядро – это непосредственно тот элемент, который отвечает за математические вычисления, согласно принятому в нем алгоритму. Процессор можно назвать своего рода «коробкой» для ядер, он объединяет их и обеспечивает взаимодействие с остальными компонентами системы.

Коротко по сути и маленькая предыстория

Технология Hyper-threading дает возможность хранения двух потоков одновременно. Поэтому при использовании операционной системы Windows, процессор на 2 ядра имеет в своем активе 4 потока. Такие вычислители еще часто называют процессорами, поддерживающими Hyper-treading (гипертрейдинг).

Дорогие и высокопроизводительные процессоры содержат ядра и потоки. Многие считают, что это смежные понятия, однако это не до конца верно. Впервые потоки появились еще в те времена, когда на рынке технологий царствовал Pentium 4.

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

Программ, которые могли корректно использовать данное преимущество было не много, если вообще были. Эта разработка находилась на стадии, своего рода, полевых исследований.

Система сама все о себе знает

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

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

Этот инструмент удобен, часто бывает полезен и обладает интуитивно понятным интерфейсом. Для того, чтобы открыть это приложение, нужно одновременно зажать клавиши Ctrl+Alt+Delete.

Так это выглядит на Windows 10. Пользователи Mac OS найдут на своем компьютере утилиту «Принудительное завершение программ», которое легко вызвать при помощи клавиш cmd alt Esc. Она также дает возможность закрыть программу, которая перестала отвечать. Еще одна популярная операционная система с открытым исходным кодом, Linux, тоже содержит диспетчер задач, только называется он по-другому – «Системный монитор».

Добраться до него помогут 3 простых шага:

  1. Системные утилиты
  2. Системный монитор

или можно воспользоваться командой

gnome-system-monitor.

Функционал «Системного монитора» полностью соответствуют таковым в «Диспетчере задач» Windows и «Принудительному завершению программ» в операционной системе от компании Apple.

Почему так быстрее

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

Количество потоков всегда вдвое больше, нежели количество ядер (при наличии «на борту» технологии HT). 2 ядра равнозначно 4-ем потокам, 4 ядра равнозначно 8-и потокам. Алгоритм просчета не может бить иным. Авторство разработки принадлежит компании Intel, являющейся лидером в производстве процессоров на массовом потребительском рынке.

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

Пошаговое руководство для новичков

Соответственно, чтобы узнать количество потоков, необходимо выяснить количество ядер, содержащихся в процессоре. Для это есть 3 (как минимум) способа:

1. Документация устройства, в которой подробно указаны характеристики. 2. Интернет, где можно ввести модель ноутбука и посмотреть, что находится у него «под капотом».

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

vacenko.ru

Технология Hyper-Threading от Intel

В прошлом мы рассказывали о технологии одновременной многопоточности (Simultaneous Multi-Threading - SMT), которая применяется в процессорах Intel. И хотя первоначально она создавалась под кодовым именем "технология Джексона" (Jackson Technology) как возможный, вероятный вариант, Intel официально анонсировала свою технологию на форуме IDF прошлой осенью. Кодовое имя Jackson было заменено более подходящим Hyper-Threading. Итак, для того чтобы разобраться, как работает новая технология, нам нужны кое-какие первоначальные знания. А именно, нам нужно знать, что такое поток, как выполняются эти потоки. Почему работает приложение? Как процессор узнает, какие операции и над какими данными он должен совершать? Вся эта информация содержится в откомпилированном коде выполняемого приложения. И как только приложение получает от пользователя какую-либо команду, какие-либо данные, – процессору сразу же отправляются потоки, в результате чего он и выполняет то, что должен выполнить в ответ на запрос пользователя. С точки зрения процессора, поток – это набор инструкций, которые необходимо выполнить. Когда в вас попадает снаряд в Quake III Arena, или когда вы открываете документ Microsoft Word, процессору посылается определенный набор инструкций, которые он должен выполнить.

Процессор точно знает, где брать эти инструкции. Для этой цели предназначен редко упоминаемый регистр, называемый счетчиком команд (Program Counter, PC). Этот регистр указывает на место в памяти, где хранится следующая для выполнения команда. Когда поток отправляется на процессор, адрес памяти потока загружается в этот счетчик команд, чтобы процессор знал, с какого именно места нужно начать выполнение. После каждой инструкции значение этого регистра увеличивается. Весь этот процесс выполняется до завершения потока. По окончании выполнения потока, в счетчик команд заносится адрес следующей инструкции, которую нужно выполнить. Потоки могут прерывать друг друга, при этом процессор запоминает значение счетчика команд в стеке и загружает в счетчик новое значение. Но ограничение в этом процессе все равно существует – в каждую единицу времени можно выполнять лишь один поток.

Существует общеизвестный способ решения данной проблемы. Заключается он в использовании двух процессоров – если один процессор в каждый момент времени может выполнять один поток, то два процессора за ту же единицу времени могут выполнять уже два потока. Отметим, что этот способ не идеален. При нем возникает множество других проблем. С некоторыми, вы уже, вероятно, знакомы. Во-первых, несколько процессоров всегда дороже, чем один. Во-вторых, управлять двумя процессорами тоже не так-то просто. Кроме того, не стоит забывать о разделении ресурсов между процессорами. Например, до появления чипсета AMD 760MP, все x86 платформы с поддержкой многопроцессорности разделяли всю пропускную способность системной шины между всеми имеющимися процессорами. Но основной недостаток в другом – для такой работы и приложения, и сама операционная система должны поддерживать многопроцессорность. Способность распределить выполнение нескольких потоков по ресурсам компьютера часто называют многопоточностью. При этом и операционная система должна поддерживать многопоточность. Приложения также должны поддерживать многопоточность, чтобы максимально эффективно использовать ресурсы компьютера. Не забывайте об этом, когда мы будем рассматривать ещё один подход решения проблемы многопоточности, новую технологию Hyper-Threading от Intel.

Производительности всегда мало

Об эффективности всегда много говорят. И не только в корпоративном окружении, в каких-то серьезных проектах, но и в повседневной жизни. Говорят, homo sapiens лишь частично задействуют возможности своего мозга. То же самое относится и к процессорам современных компьютеров.

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

Чтобы проиллюстрировать ситуацию, давайте вообразим себе процессор с тремя исполнительными устройствами: арифметико-логическим (целочисленным – ALU), устройством для работы с плавающей точкой (FPU), и устройством загрузки/хранения (для записи и чтения данных из памяти). Кроме того, предположим, что наш процессор может выполнять любую операцию за один такт и может распределять операции по всем трем устройствам одновременно. Давайте представим, что к этому процессору на выполнение отправляется поток из следующих инструкций:

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

Итак, вы видите, что в каждый такт используется только 33% всех исполнительных устройств. В этот раз FPU остается вообще незадействованным. В соответствии с данными Intel, большинство программ для IA-32 x86 используют не более 35% исполнительных устройств процессора Pentium 4.

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

И снова загруженность исполнительных устройств составляет лишь на 33%.

Хорошим выходом из данной ситуации будет параллелизм на уровне инструкций (Instruction Level Parallelism - ILP). В этом случае одновременно выполняются сразу нескольких инструкций, поскольку процессор способен заполнять сразу несколько параллельных исполнительных устройств. К сожалению, большинство x86 программ не приспособлены к ILP в должной степени. Поэтому приходится изыскивать другие способы увеличения производительности. Так, например, если бы в системе использовалось сразу два процессора, то можно было бы одновременно выполнять сразу два потока. Такое решение называется параллелизмом на уровне потоков (thread-level parallelism, TLP). К слову сказать, такое решение достаточно дорогое.

Какие же ещё существуют способы увеличения исполнительной мощи современных процессоров архитектуры x86?

Hyper-Threading

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

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

Hyper-Threading – это название технологии, существовавшей и ранее вне x86 мира, технологии одновременной многопоточности (Simultaneous Multi-Threading, SMT). Идея этой технологии проста. Один физический процессор представляется операционной системе как два логических процессора, и операционная система не видит разницы между одним SMT процессором или двумя обычными процессорами. В обоих случаях операционная система направляет потоки как на двухпроцессорную систему. Далее все вопросы решаются на аппаратном уровне.

В процессоре с Hyper-Threading каждый логический процессор имеет свой собственный набор регистров (включая и отдельный счетчик команд), а чтобы не усложнять технологию, в ней не реализуется одновременное выполнение инструкций выборки/декодирования в двух потоках. То есть такие инструкции выполняются поочередно. Параллельно же выполняются лишь обычные команды.

Официально технология была объявлена на форуме Intel Developer Forum прошлой осенью. Технология демонстрировалась на процессоре Xeon, где проводился рендеринг с помощью Maya. В этом тесте Xeon с Hyper-Threading показал на 30% лучшие результаты, чем стандартный Xeon. Приятный прирост производительности, но больше всего интересно то, что технология уже присутствует в ядрах Pentium 4 и Xeon, только она выключена.

Технология пока ещё не выпущена, однако те из вас, кто приобрел 0,13 мкм Xeon, и установил этот процессор на платы с обновленным BIOS, наверняка были удивлены, увидев в BIOS опцию включения/отключения Hyper-Threading.

А пока Intel будет оставлять опцию Hyper-Threading отключенной по умолчанию. Впрочем, для ее включения достаточно просто обновить BIOS. Все это касается рабочих станций и серверов, что же до рынка персональных компьютеров, в ближайшем будущем у компании планов касательно этой технологии не имеется. Хотя возможно, производители материнских плат предоставят возможность включить Hyper-Threading с помощью специального BIOS.

Остается очень интересный вопрос, почему Intel хочет оставить эту опцию выключенной?

Углубляемся в технологию

Помните те два потока из предыдущих примеров? Давайте на этот раз предположим, что наш процессор оснащен Hyper-Threading. Посмотрим, что получится, если мы попытаемся одновременно выполнить эти два потока:

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

Итак, что же мы видим? Параллелизм на уровне потоков дал сбой – исполнительные устройства стали использоваться ещё менее эффективно. Вместо параллельного выполнения потоков, процессор выполняет их медленнее, чем если бы он выполнял их без Hyper-Threading. Причина довольно проста. Мы пытались одновременно выполнить сразу два очень похожих потока. Ведь оба они состоят из операций по загрузке/сохранению и операций сложения. Если бы мы параллельно запускали "целочисленное" приложение и приложение, работающее с плавающей точкой, мы бы оказались куда в лучшей ситуации. Как видим, эффективность Hyper-Threading сильно зависит от вида нагрузки на ПК.

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

На рабочих же станциях возможностей для увеличения производительности у Hyper-Threading больше. Но с другой стороны, все зависит от конкретного использования компьютера. Рабочая станция может означать как high-end компьютер для обработки 3D графики, так и просто сильно нагруженный компьютер.

Наибольший же прирост в производительности от использования Hyper-Threading наблюдается в серверных приложениях. Главным образом это объясняется широким разнообразием посылаемых процессору операций. Сервер баз данных, использующих транзакции, может работать на 20-30% быстрее при включенной опции Hyper-Threading. Чуть меньший прирост производительности наблюдается на веб-серверах и в других сферах.

Максимум эффективности от Hyper-Threading

Вы думаете, Intel разработала Hyper-Threading только лишь для своей линейки серверных процессоров? Конечно же, нет. Если бы это было так, они бы не стали впустую тратить место на кристалле других своих процессоров. По сути, архитектура NetBurst, использующаяся в Pentium 4 и Xeon, как нельзя лучше подходит для ядра с поддержкой одновременной многопоточности. Давайте ещё раз представим себе процессор. На этот раз в нем будет ещё одно исполнительное устройство – второе целочисленное устройство. Посмотрим, что случится, если потоки будут выполняться обоими устройствами:

С использованием второго целочисленного устройства, единственный конфликт случился только на последней операции. Наш теоретический процессор в чем-то похож на Pentium 4. В нем имеется целых три целочисленных устройства (два ALU и одно медленное целочисленное устройство для циклических сдвигов). А что ещё более важно, оба целочисленных устройства Pentium 4 способны работать с двойной скоростью – выполнять по две микрооперации за такт. А это, в свою очередь, означает, что любое из этих двух целочисленных устройств Pentium 4/Xeon могло выполнить те две операции сложения из разных потоков за один такт.

Но это не решает нашей проблемы. Было бы мало смысла просто добавлять в процессор дополнительные исполнительные устройства с целью увеличения производительности от использования Hyper-Threading. С точки зрения занимаемого на кремнии пространства это было бы крайне дорого. Вместо этого, Intel предложила разработчикам оптимизировать программы под Hyper-Threading.

Используя инструкцию HALT, можно приостановить работу одного из логических процессоров, и тем самым увеличить производительность приложений, которые не выигрывают от Hyper-Threading. Итак, приложение не станет работать медленнее, вместо этого один из логических процессоров будет остановлен, и система будет работать на одном логическом процессоре – производительность будет такой же, что и на однопроцессорных компьютерах. Затем, когда приложение сочтет, что от Hyper-Threading оно выиграет в производительности, второй логический процессор просто возобновит свою работу.

На веб-сайте Intel имеется презентация, описывающая, как именно необходимо программировать, чтобы извлечь из Hyper-Threading максимум выгоды.

Выводы

Хотя мы все были крайне обрадованы, когда до нас дошли слухи об использовании Hyper-Threading в ядрах всех современных Pentium 4/Xeon, все же это не будет бесплатной производительностью на все случаи жизни. Причины ясны, и технологии предстоит преодолеть ещё многое, прежде чем мы увидим Hyper-Threading, работающую на всех платформах, включая домашние компьютеры. А при поддержке разработчиков, технология определенно может оказаться хорошим союзником Pentium 4, Xeon, и процессорам будущего поколения от Intel.

При существующих ограничениях и при имеющейся технологии упаковки, Hyper-Threading кажется более разумным выбором для потребительского рынка, чем, например, подход AMD в SledgeHammer – в этих процессорах используется целых два ядра. И до тех пор, пока не станут совершенными технологии упаковки, такие как Bumpless Build-Up Layer, стоимость разработки многоядерных процессоров может оказаться слишком высокой.

Интересно заметить, насколько разными стали AMD и Intel за последние несколько лет. Ведь когда-то AMD практически копировала процессоры Intel. Теперь же компании выработали принципиально иные подходы к будущим процессорам для серверов и рабочих станций. AMD на самом деле проделала очень длинный путь. И если в процессорах Sledge Hammer действительно будут использоваться два ядра, то по производительности такое решение будет эффективнее, чем Hyper-Threading. Ведь в этом случае кроме удвоения количества всех исполнительных устройств снимаются проблемы, которые мы описали выше.

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

Если вы заметили ошибку - выделите ее мышью и нажмите CTRL+ENTER.

3dnews.ru

Чем процесс отличается от потока?… | БCБ на WordPress.com

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

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

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

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

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

Любой поток состоит из двух компонентов:

объекта ядра, через который операционная система управляет потоком. Там же хранится статистическая информация о потоке(дополнительные потоки создаются также ядром); стека потока, который содержит параметры всех функций и локальные переменные, необходимые потоку для выполнения кода.

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

Я решил не рассказывать о многопоточном программировании сегодня, тем более что есть отличные мануалы по этой теме(ссылка внизу), а просто познакомиться с тем какие средства есть у CSharp для взаимодействия с потоками и процессами. А что рассказывать? MSDN в соседнее от окошка Class1.cs и вперед…=)

Понять пост не читая или для ленивых:

  1. Поток (thread) определяет последовательность исполнения кода в процессе.
  2. Процесс ничего не исполняет, он просто служит контейнером потоков.
  3. Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах.
  4. Потоки могут исполнять один и тот же код и манипулировать одними и теми же данными, а также совместно использовать описатели объектов ядра, поскольку таблица описателей создается не в отдельных потоках, а в процессах.
  5. Так как потоки расходуют существенно меньше ресурсов, чем процессы, старайтесь решать свои задачи за счет использования дополнительных потоков и избегайте создания новых процессов(но подходите к этому с умом).

  6. Как протестировать материнскую плату

Многоядерностью процессоров в нынешнее время никого не удивишь. Наоборот, все стараются чтобы их компьютер поддерживал как можно больше ядер, а следовательно быстрее работал, и это правильно.
Если касаться именно процессоров, то уже давно на рынке встречаются только два производителя - это 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 ) и увидеть там.

У многих процессоров Intel есть поддержка технологии под названием Hyper-threading. Данная технология позволяет выполнять сразу 2 потока команд на одном ядре процессора. Таким образом удается более эффективно использовать вычислительную мощность ядра. Но, технология Hyper-threading используется далеко не во всех процессорах Intel. Технология Hyper-threading присутствует в , а также в некоторых новых Pentium и мобильных Core i5.

У процессоров AMD с архитектурой Zen также есть технология, создающая по два потока вычислений на ядро. И у AMD также не все процессоры получают поддержку данной технологии.

Из-за такого разброса в характеристиках процессоров создается путаница и пользователи часто не могут разобраться, в каких процессорах сколько потоков используется. В данной статье речь пойдет о том, как узнать сколько потоков на вашем процессоре.

Способ № 1. Диспетчер задач.

Самый простой способ узнать сколько потоков , это посмотреть в «Диспетчере задач». Для можно воспользоваться классической комбинацией клавиш CTRL-SHIFT-DELETE. Если у вас операционная система Windows 7 или более новая, то это можно сделать еще и с помощью CTRL-SHIFT-ESC.

После открытия «Диспетчера задач» нужно перейти на вкладку «Быстродействие».

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

Если у вас Windows 8 или Windows 10, то хронология нагрузки на процессор может отображаться одним графиком. В этом случае вам нужно сначала переключиться на отображение хронологии по логическим процессорам (потокам). Для этого нужно кликнуть правой кнопкой мышки и выбрать «Изменить график – Логические процессоры».

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

Кроме этого, в «Диспетчере задач» Windows 8/10 прямым текстом указывается сколько потоков в процессоре. Сразу под графиками есть блок с информацией. Там в строке «Логические процессоры» указано количество потоков процессора.

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

Способ № 2. Программы.

Пожалуй, самой известной программой для получения информации о характеристиках процессора является программа CPU-Z. Данная программа является бесплатной, и вы можете . Если вы хотите узнать сколько потоков в процессоре, то вам нужно запустить CPU-Z на своем компьютере и посмотреть значение «Threads», которое находится в правом нижнем углу программы на вкладке «CPU». На скриншоте внизу видно, что у процессора 4 потока.

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

Среди прочего с ее помощью можно узнать и количество потоков процессора. Для этого нужно перейти в раздел «CPU» и посмотреть значение «Threads».



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: