Под многозадачностью операционной системы windows понимается

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

Содержание

  1. Многозадачность в операционной системе windows
  2. 04 — Архитектура ЭВМ. Процессы, потоки, многозадачность
  3. Основы многозадачности
  4. Многозадачность в Windows
  5. Основные понятия
  6. Многозадачность
  7. Что такое многозадачность?
  8. Как работать в таком режиме?
  9. Плюсы и минусы
  10. Резюме
  11. Многозадачность в операционной системе Windows

Многозадачность в операционной системе windows

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

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

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

Переключение по событию

Переключение задач по событию показано на рис 1.

mnogozadachnost v operacionnoj sisteme windows 1

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

Переключение по времени

Переключение задач по времени показано на рис 2.

mnogozadachnost v operacionnoj sisteme windows 2

Рис 2. Переключение задач по времени.

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

Многозадачность в операционной системе Windows

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

1. Прерывание от таймера. Это означает, что время, предоставленное активной задаче, истекло. Планировщик прекращает ее выполнение и передает управление задаче с наибольшим приоритетом. Такое переключение происходит наиболее часто.

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

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

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

В Windows каждая запущенная 32- х битовая программа называется процессом. Процесс в основном имеет дело с распределением ресурсов системы. Исполняемый код для системы является другим объектом, называемым нитью, или потоком управления (thread). Когда запускается новый процесс, ему автоматически придается одна нить. Нити (потоки) используются операционной системой Windows для диспетчеризации времени процессора. Диспетчеризация — это метод выделения времени каждой из нитей (не процессов, поскольку процесс может иметь несколько нитей). Операционная система рассматривает все готовые к запуску потоки и выбирает для выполнения один из них. Диспетчер также определяет квант времени, предоставляемый для выполнения каждому из потоков.

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

ОПИСАНИЕ ЛАБОРАТОРНОЙ РАБОТЫ

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

04 — Архитектура ЭВМ. Процессы, потоки, многозадачность

Источник

Основы многозадачности

Многозадачность в Windows

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

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

Основные понятия

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

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

Мультипроцессирование

6 1

6 2

6 3

6 4

Windows содержит встроенные механизмы, необходимые для работы на SMP; также возможна установка этой ОС на cc-NUMA системах (современные версии Windows имеют механизмы поддержки cc-NUMA систем). Специальных, встроенных в ОС средств для исполнения приложений на MPP системах в Windows не предусмотрено. Windows предполагает альтернативное применение MPP систем, построенных на обычных сетях, для реализации web- или файловых серверов с балансировкой нагрузки по узлам кластера.

Мультипрограммирование

Мультипрограммирование (то есть одновременное выполнение разного кода на одном или нескольких процессорах) возможно и без реального мультипроцессирования. Конечно, при наличии только одного процессора должен существовать некоторый механизм, обеспечивающий переключение процессора между разными выполняемыми потоками. Такой режим разделения процессорного времени позволяет одному процессору обслуживать несколько задач «как бы одновременно»: осуществляя быстрое переключение между разными задачами и выполняя в данный момент времени код только одной задачи, процессор создает иллюзию одновременного выполнения кода разных задач. Более того, даже на многопроцессорных системах при реальной возможности распараллеливания задач по разным процессорам, обычно используют механизм разделения времени на каждом из доступных процессоров. Формально мультипрограммирование предполагает именно разделение процессорного времени, поэтому иногда его противопоставляют мультипроцессированию: реализация многозадачности на одном процессоре в противовес использованию многих процессоров.

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

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

6 5

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

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

6 6

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

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

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

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

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

6 7

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

Реализации Windows NT, 2000, XP, 2003+ предусматривают достаточно развитый и сложный планировщик, учитывающий множество факторов и корректирующий как назначение и длительность отводимых задаче квантов, так и приоритеты задач. При этом планировщик является настраиваемым, и его логика работы несколько отличается в зависимости от настроек системы (некоторые доступны через панель управления) и от назначения системы (работа планировщика различна у серверов и рабочих станций).

Базовая терминология

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

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

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

В Windows для обозначения этих понятий использованы термины process (процесс), thread (поток) и fiber (волокно). Достаточно часто термин «thread» переводится на русский язык как «нить», а не «поток». Термин » fiber » также может переводиться либо как «нить», либо как «волокно». Поток соответствует потоку ядра и планируется ядром операционной системы, а волокно соответствует потоку пользователя и планируется в приложении пользователя.

Источник

Многозадачность

11cfd3adc008332b20f2c34aa8cc6795
Когда в начале 60-х годов прошлого века создали первую операционную систему IBM, пользователей поразила возможность компьютера выполнять несколько функций одновременно. То есть процессор легко переключался с одной задачи на другую, постепенно доводя их все до логического завершения. Впечатлившись таким эффектом, мультизадачность попробовали перенести в сферу человеческой деятельности. Тогда показалось, что умение выполнять несколько дел одновременно – это очень полезный навык, овладев которым можно кратно повысить эффективность в работе при этом сэкономив уйму времени. Так ли это на самом деле? Давайте разбираться.

Что такое многозадачность?

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

c654633cdabb653af7a7904c0bd8e912

Скорей всего вы не раз слышали о выдающихся способностях Цезаря делать одновременно два и больше дел. Воодушевившись таким «подвигом», вы «задвинули» усердие в выполнении одного дела на дальнюю полку и попробовали переключаться с одной задачи на другую, потом на третью и так далее. Всего по чуть-чуть и что в итоге?

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

Умение работать в режиме многозадачности – это не такой уж полезный и ценный навык, как кажется на первый взгляд. Исследования показывают, что мультизадачность вредит трудоспособности человека. Мы не роботы к счастью, поэтому продуктивность работы во многом зависит от умения концентрироваться на выполнении одной задачи. Цепочку дел мы выполняем последовательно, завершая одно и приступая к другому. По мере достижения целей растет мотивация и желание добиваться больших успехов, экономится время. Казалось бы, схватившись за два дела сразу, время на выполнение задач должно сократиться наполовину. Но в действительности потребуется вдвое больше усилий и при этом шансы на успешное завершение сократятся.

91a91d6c1592177dce41c7b55eb3b63d

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

А теперь сделайте те же простые задачи последовательно: сначала тарелки, потом поливка и в завершении отправка сообщений. Вы удивитесь – и дела идут быстрее и мозг цел!

Усложним нагрузку, а точнее сделаем приближенной к реальности. Например, вы пишите отчет или презентацию и одновременно проверяете новые сообщения в одноклассниках или ВК, отвечаете на смс или просьбы коллег помочь по «неотложному» делу. В 99% случаев, работая в режиме такой многозадачности, вы заметите, что время утекло непонятно куда, рабочий настрой улетучился, а основной работы сделано всего 10-15%. Шокирующий вывод: чем больше вы отвлекаетесь, тем сложнее сосредоточиться на работе. Гаджеты, аккаунты в соцсетях, email-почта и другое – это пожиратели времени и усилий, которые вы могли бы с куда большей пользой потратить на полезное дело.

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

Как работать в таком режиме?

c9109c8079f85fc637fbcc0b5afd89fc

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

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

Плюсы и минусы

Рассмотрим преимущества мультизадачности:

17dfc16f1e1b7610c29ed06eef6786c7

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

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

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

Резюме

Мы узнали, что такое многозадачность. Изучили, как работать в таком режиме, какие есть плюсы и минусы выполнения нескольких дел одновременно. Мультизадачность можно использовать для тренировки пластичности мозга, однако в рабочей среде полезнее развивать навык последовательного выполнения дел. Тише едешь – дальше будешь!

Источник

Многозадачность в операционной системе Windows

ТЕОРЕТИЧЕСКОЕ ОПИСАНИЕ

Многозадачность

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

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

Переключение по событию

Переключение задач по событию показано на рис 1.

image002

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

Переключение по времени

Переключение задач по времени показано на рис 2.

image004

Рис 2. Переключение задач по времени.

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

Многозадачность в операционной системе Windows

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

1. Прерывание от таймера. Это означает, что время, предоставленное активной задаче, истекло. Планировщик прекращает ее выполнение и передает управление задаче с наибольшим приоритетом. Такое переключение происходит наиболее часто.

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

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

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

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

ОПИСАНИЕ ЛАБОРАТОРНОЙ РАБОТЫ

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

Источник

2.2.1.
Основные
принципы
многозадачности
в Windows

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

странство (4Gb).
Процесс состоит из кода, данных и других
системных ресурсов, таких

как открытые файлы, каналы
(pipes), синхронизирующие объекты. Однако процесс

статический объект,
который сам по себе действия не производит.
Поток (thread) — базо-

вый объект,
которому операционная система
распределяет время центрального процес-

сора. Поток выполняет
команды программы с учетом заданного
ему маршрута. Каждый

57

процесс представляет собой
один начальный поток, который иногда
называют первич-

ным
потоком.

Первичный поток способен создать вторичные потоки. Все потоки, принадлежа-

щие одному процессу,
имеют совместный доступ к его ресурсам.
Все они работают под

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

ным переменным,
записывают информацию в одну и ту же
область памяти и имеют дос-

туп к одним и тем
же объектам. В целом следует отметить,
что программа может выпол-

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

запуска
«дочернего» процесса необходимо временно приостанавливать основной про-

цесс, что приводит
к замедлению выполнения программы в
целом. Дополнительные по-

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

асинхронные операции, работает
одновременно с несколькими окнами.

Организация многозадачности в
MS Windows различается в линейках 9x и NT. В

Windows
9x реализована приоритетная многозадачность.
В данном случае каждому

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

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

дующему потоку.
Это не дает возможность программам
полностью захватывать ресурсы

процессора.

Windows
NT использует вытесняющую
многозадачность.
Выполнение всех про-

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

каждой из программ
некоторое количество процессорного
времени и периодически про-

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

к специальному
системному вызову, вы можете как бы
приостановить (sleep) выполне-

ние программы,
однако если вы этого не сделаете, со
временем операционная система

сделает это за
вас. Подвисание одной из программ не
приведет к подвисанию всей сис-

темы.

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

лее подробно, выглядит
привлекательней. Однако
за все приходится платить. И в пер-

вую очередь расплачиваться приходится программистам, которые
разрабатывают при-

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

Представьте себе, что на компьютере
работает несколько программ, использующих
один

и тот же файл журнала ошибок. Если вам
необходимо сделать запись в этом файле,
то в

Windows 9x вы можете
без лишних сложностей открыть файл,
записать в него данные, а

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

функциям, вы можете
быть уверенными, что в то время, пока вы
работали с файлом, ни

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

боты с файлом
на компьютере работает только одна
ваша программа, а все остальные

программы находятся в состоянии
ожидания).

В среде Windows NT все
не так просто. Предположим, что один из
потоков открыл

файл и начал в него
запись, но в этот момент операционная система
передала управле-

ние другому потоку.
Что произойдет, если другой поток
попытается открыть тот же са-

мый файл? Либо
этого сделать не удастся, либо другой
поток откроет файл в режиме со-

вместного доступа
(for sharing), что может не соответствовать
вашим ожиданиям. Даже

если в ходе работы с
файлом операционная система не осуществила
передачу управле-

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

другом процессоре. В результате вы
столкнетесь с той же проблемой.

58

На системном уровне каждый поток представляет собой
объект, созданный сис-

темным менеджером
объектов. Аналогично с остальными
системными объектами, поток

содержит данные
(атрибуты) и методы
(функции). Схематически объект-поток может

быть представлен в следующем виде
(рис.2.5.) [12]:

Стандартный
объект
заголовка

Атрибуты
потока

Идентификатор клиента

Контекст

Динамический приоритет

Базовый приоритет

Привязанность к архитектуре

процессора

Время выполнения

Статус оповещения

Счетчик прерываний

Маркер передачи прав доступа

Порт завершения

Код завершения

Методы
потока

Создание потока

Открытие потока

Запрос информации о потоке

Установка информации о потоке

Текущий поток

Завершение потока

Получение контекста

Установление контекста

Прерывание

Возобновление

Предупреждение

Проверка поступления преду-

преждения

Регистрация порта завершения

Рис.2.5.
Схема
объекта
потока.

Для большинства методов потока имеются
соответствующие API — функции Win32.

Windows защищает свои внутренние структуры от прямого вмешательства пользова-

тельских программ.
В отличии от более привилегированных
программ, функционирую-

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

ровать или изменять
параметры системных объектов. Все
операции с ними выполняются

посредством функций
Win32 API. Windows предоставляет дескриптор, идентифици-

рующий объект.
При выполнении операций с объектом его
дескриптор передается в ка-

честве аргумента одной из
API-функций. Свои дескрипторы имеют потоки, процессы,

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

неджеру объектов.
Функция, создающая поток, возвращает
дескриптор нового объекта.

С помощью этого дескриптора можно
выполнить следующие операции:

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

• приостановить поток и возобновить
его выполнение;

• прекратить выполнение потока;

• определить код завершения потока.

В ОС
Windows потоки, процессы, семафоры и исключающие семафоры могут

иметь несколько разных дескрипторов. Завершив работу с объектом, необходимо вы-

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

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

лее 65536 открытых дескрипторов.

Работа
с потоками не сводится только к их
запуску и остановке. Необходимо обес-

печить совместное
функционирование потоков. Для организации
эффективного взаимо-

действия между несколькими потоками необходимо производить контроль за их вре-

менными параметрами. Контроль
осуществляется [12]:

59

• установлением приоритетов;

• синхронизацией.

Приоритет потока определяет, насколько часто
данный поток получает доступ к

центральному процессору. Синхронизация регулирует порядок обращения потоков к

общим ресурсам.
Когда системная программа-планировщик
останавливает один поток и

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

токам, имеющим наиболее высокий приоритет. Обработчики системных прерываний

всегда имеют более
высокий приоритет по сравнению с
пользовательскими процессами.

Каждому процессу
присущ собственный приоритет. Базовый
плановый приоритет пото-

ка определяется
на основе приоритета процесса, который
является владельцем этого по-

тока. Всего различают
32 уровня приоритета от 0 до 31. При этом
приоритеты уровня от

0 до 15 называются
переменными приоритетами, а от 16 до 31 –
фиксированными при-

оритетами. Схема наследования приоритетов
потока показана на рис.2.6 [12].

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

Уровни

приоритета

Класс
реального

времени

Наивысший

класс

Класс
переднего

плана

Фоновый
класс

Класс
простоя

Базовый

приоритет

процесса

Диапазон
базового

приоритета
потока,

владельцем
которо-

го
является
процесс

с
приоритетом
пе-

реднего
плана

Диапазон
дина-

мического
при-

оритета
для
то-

го
же
самого

потока

Рис.2.6
Схема
наследования
приоритета
потоков
от
исходного
приоритета
процесса

60

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

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

который не может
быть выше или ниже приоритета
процесса-владельца более чем на 2

уровня.
Операционная система способствует
«продвижению» потока для его выполне-

ния. Для этого система поддерживает динамический приоритет потоков, которые вы-

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

считывает
данные с диска временно повышается
приоритет всех потоков такого процес-

са. Эти временные
приращения в сумме с базовым приоритетом
образуют динамический

приоритет процесса.
Планировщик определяет очередность
выполнения потоков на ос-

новании их динамического приоритета. Со следующим тактом процесса приращение

приоритета начинает
уменьшаться на один уровень, постепенно
достигая уровня базово-

го приоритета.

Выбирая поток,
который будет выполняться следующим,
программа-планировщик

начинает просмотр
очереди заданий с потоков, имеющий
наивысший приоритет, выпол-

няет
их, а затем переходит к остальным потокам.
Однако иногда в очереди заданий со-

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

приостановлены
или заблокированы. В каждый момент
времени поток может находить-

ся в одном из шести состояний.

Ready(готов) — поставлен в очередь и
ожидает выполнения.

Standby(ближайший) — готов быть выполненным
следующим.

Running
(выполнение) — находится в режиме
выполнения и взаимодействует с централь-

ным процессором.

Waiting(ожидание) не выполняется, ожидая
сигнала выполнения.

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

контекст.

Terminated(завершен) — выполнение
завершено, однако объект не удален.

Когда
программа-планировщик выбирает из
очереди готовый к выполнению поток,

она
загружает его контекст.
В состав контекста входит набор значений
регистров про-

цессора, стек ядра,
блок параметров окружения потока и
пользовательский стек в адрес-

ном пространстве процесса, который является владельцем данного потока. Если часть

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

пока система соберет все составные
части контекста.

Чтобы потоки могли надежно работать,
их необходимо синхронизировать. Пред-

ставьте себе, что
один поток создает кисть, а затем создает
несколько потоков, которые

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

должен уничтожать
кисть до тех пор, пока другие потоки не
завершат операции рисова-

ния. Или представьте
себе, что один поток принимает данные,
введенные пользователем,

и записывает их в
файл, а другие потоки считывают данные
из этого файла и образовы-

вают веденный
текст. Считывание не должно происходить
в тот момент, когда идет за-

пись. В обоих случаях
надо принять меры по
координации последовательности опера-

ций в нескольких потоков.

Одно из возможных
решений заключается в создании глобальной
переменной типа

Boolean, которую один из потоков будет
использовать с целью информирования
других

потоков о том, что
объект занят. Например, поток, записывающий
данные в файл, может

присвоить
переменной bDone
значение TRUE,
а потоки, считывающие данные из файла,

будут циклически
просматривать эту переменную до тех
пор, пока ее значение не изме-

нится. Такая схема вполне работоспособна, однако циклический просмотр флага не-

сколькими потоками
занимает много времени процессора. Вот
почему в Win32 поддер-

живается набор синхронизирующих объектов
[9, 12]. Перечислим их.

Объект типа
исключающий семафор функционирует
подобно узкой двери, «про-

пуская» (т.е. давая допуск) одновременно
по одному потоку.

61

Объект типа семафор
функционирует подобно многостворчатой
двери, ограничи-

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

Объект
типа события
передает глобальный сигнал, воспринимаемый
любым пото-

ком, для которого он адресован.

Объект
типа критический
раздел
аналогичен исключающему семафору, но
рабо-

тает только в пределах одного процесса.

Все указные объекты являются системными и создаются менеджером объектов.

Хотя каждый
синхронизирующий объект координирует
определенный вид взаимодейст-

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

ределенную
синхронизируемую операцию, ожидает
ответ от одного из этих объектов и

осуществляет свои функции только после получения на то разрешения. Программа-

планировщик удаляет
ожидающие объекты из очереди запуска,
с тем чтобы они не за-

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

планировщик
возобновляет работу потока. Место и
способ получения сигнала зависит

от конкретного объекта.

Исключающие семафоры, обычные семафоры и события позволяют координиро-

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

разделы воспринимаются лишь потоками одного процесса. Если
один процесс создает

другой процесс,
дочерний процесс часто наследует
дескрипторы имеющихся синхрони-

зирующих объектов. Объекты критических
разделов не могу быть унаследованы.

С фундаментальной точке зрения, синхронизирующий объект, подобно другим

системным объектам,
представляет собой структуру данных. Синхронизирующие объ-

екты могут находиться
в двух состояниях: при наличии сигнала
и при отсутствии тако-

вого. Потоки
взаимодействуют с синхронизирующими объектами
путем установки сиг-

нала или путем его
ожидания. Поток, находящейся в состоянии
ожидания, блокируется

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

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

включает сигнал и освобождает объект.

Потоки могут
ожидать разрешения не только от
исключающих и обычных семафо-

ров, событий и
критических разделов, но и от других
объектов. Иногда возникает ситуа-

ция,
когда необходимо ожидать разрешения от процесса,
другого потока, таймера или

файлового объекта.
Все эти объекты имеют свое предназначение,
но подобно синхрони-

зирующим объектом
они способны давать сигналы разрешения.
Процессы и потоки сиг-

нализируют о своем завершении, объекты-таймеры
— об истечении определенного ин-

тервала времени, а файловые объекты
— о завершении операций чтения или записей

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

2.2.2. API-функции
для
реализации
механизма
многозадачности

В Win32 API определены
следующие функции работы с процессами
и потоками [4]

(таблица 2.1.)

Таблица
2.1

Название функции

1

AttachThreadInput

CommandLineToArgvW

CreateProcess

CreateRemoteThread

CreateThread

Выполняемое действие

2

Переключение механизмов ввода с одной
нити на дру-

гую

Производит разбор командной строки в
Unicode

Создает процесс

Создает поток в адресном пространстве
другого про-

цесса

Создает поток

62

1

2

Продолжение
табл. 2.1

ExitProcess

ExitThread

FreeEnvironmentStrings

GetCommandLine

GetCurrentProcess

GetCurrentProcessId

GetCurrentThread

GetCurrentThreadId

GetEnvironmentStrings

GetEnvironmentVariable

GetExitCodeProcess

GetExitCodeThread

GetPriorityClass

GetProcessAffinityMask

GetProcessShutdownParame-

ters

GetProcessTimes

GetCurrentProcess

GetProcessWorkingSetSize

GetStartupInfo

GetThreadPriority

GetThreadTimes

OpenProcess

ResumeThread

SetEnvironmentVariable

SetPriorityClass

Завершает процесс и все его потоки

Завершает поток

Освобождает память области переменных
среды

Возвращает указатель на командную
строку

Возвращает описатель (handle) текущего
процесса

Возвращает идентификатор текущего
процесса

Возвращает описатель
(handle) текущего потока

Возвращает идентификатор текущего
потока

Возвращает строку переменных среды

Возвращает значение указанной переменной
среды

Возвращает код завершения процесса

Возвращает код завершения потока

Возвращает класс приоритета процесса

Сообщает, на каких процессорах разрешено
исполне-

ние процесса

Сообщает параметры поведения процесса
при завер-

шении работы системы

Возвращает временные характеристики
процесса

Сообщает версию Windows, для которой
предназна-

чен процесс

Возвращает характеристики доступного
процессу ад-

ресного пространства

Возвращает параметры процесса, полученные
им при

создании

Сообщает приоритет указанного потока

Возвращает временные характеристики
указанного

потока

Возвращает описатель (handle) указанного
процесса

Уменьшает счетчик задержаний потока
(или запуска-

ет его)

Устанавливает значение указанной
переменной среды

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

SetProcessShutdownParameters Устанавливает параметры
поведения процесса при

завершении работы системы

SetThreadAffinityMask

SetThreadPriority

Sleep

SleepEx

SetProcessWorkingSetSize

SuspendThread

TerminateProcess

TerminateThread

TlsAlloc

Устанавливает, на каких процессорах
разрешено ис-

полнение потока

Устанавливает приоритет указанного
потока

Задерживает исполнение потока на
указанное коли-

чество миллисекунд

Задерживает исполнение до наступления
события

ввода/вывода или на время

Устанавливает характеристики доступного
процессу

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

Приостанавливает исполнение указанного
потока

Завершает указанный процесс

Завершает указанный поток

Распределяет индекс локальной памяти
потока

(thread local storage TLS)

63

TlsFree

1

Освобождает индекс TLS

2

Окончание
табл. 2.1

TlsGetValue

TlsSetValue

Возвращает данные, размещенные в TLS с
указанным индексом

Помещает данные в TLS с указанным индексом

WaitForInputIdle Ждет, пока не начнется ввод
для указанного процесса

WinExec

Выполняет указанное приложение

Подробное описание
функций приведено в Win32 Programmer’s
Reference. Далее

рассмотрим только некоторые основные
функции [4].

Функция
CreateProcess() — создает новый процесс и его первичный поток. Новый

процесс исполняет указанный исполняемый
файл. Формат функции:

BOOL CreateProcess(LPCTSTR lpApplicationName,
// имя исполняемого файла

LPTSTR lpCommandLine, // командная строка

LPSECURITY_ATTRIBUTES lpProcessAttributes, // атрибуты
защиты процесса

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибуты защиты
потока

BOOL bInheritHandles, // флаг наследования
описателей

DWORD dwCreationFlags, // флаги создания

LPVOID lpEnvironment, // указатель блока переменных
среды

LPCTSTR lpCurrentDirectory, // текущий каталог

LPSTARTUPINFO lpStartupInfo, // блок начальных
параметров

LPPROCESS_INFORMATION lpProcessInformation //
указатель

// структуры, описывающей порожденный
процесс

);

Функция возвращает TRUE в случае успеха
и FALSE — в случае неудачи.

Параметры:

lpApplicationName
— указатель на строку, содержащую имя исполняемой программы.

Имя может быть
полное. Если оно не полное, то поиск
файла производится в теку-

щем каталоге. Параметру может быть
присвоено значение NULL. В этом случае в

качестве имени
файла выступает первая выделенная пробелами
лексема из строки

lpCommandLine;

lpCommandLine — указатель
командной строки. Если параметр
lpApplicationName имеет

значение NULL, то
имя исполняемого файла выделяется из
lpCommandLine, а по-

иск исполняемого
файла производится в соответствии с
правилами, действующими

в системе;

lpProcessAttributes —
указатель на структуру, описывающую
параметры защиты процесса.

Если параметру присвоено значение
NULL, то устанавливаются атрибуты “по

умолчанию”;

lpThreadAttributes- указатель
на структуру, описывающую параметры
защиты первично-

го
потока. Если параметру присвоено
значение NULL, то устанавливаются атрибу-

ты “по умолчанию”;

bInheritHandles
— определяет, будет ли порожденный процесс наследовать описатели

(handles) объектов
родительского процесса. Например, если
родительский процесс

AB, то он получил
описатель процесса B и может им
манипулировать. Если теперь

он порождает
процесс C с параметром bInheritHandles равным
TRUE, то и процесс

C сможет работать с описателем процесса
B;

dwCreationFlags
— определяет некоторые дополнительные условия
создания процесса и

его класс приоритета;

lpEnvironment- указатель на блок переменных
среды порожденного процесса. Если этот

параметр равен
NULL, то порожденный процесс наследует
среду родителя. Иначе

64

он должен указывать на завершающийся
нулем блок строк, каждая из которых за-

вершается нулем (аналогично
DOS);

lpCurrentDirectory — указатель
на строку, содержащую полное имя текущего
каталога по-

рожденного процесса.
Если этот параметр равен NULL, то
порожденный процесс

наследует каталог родителя;

lpStartupInfo
— указатель на структуру
STARTUPINFO, которая определяет параметры

главного окна порожденного процесса;

lpProcessInformation —
указатель на структуру, которая
будет заполнена информацией о

порожденном процессе после возврата
из функции.

Пример: программа, запускающая
Microsoft Word

#include <windows.h>

#include <conio.h>

#include <stdio.h>

main()

{

PROCESS_INFORMATION pi ;

STARTUPINFO si ;

ZeroMemory( &si, sizeof(si)) ;

si.cb = sizeof( si ) ;

printf( «Press any key to start WinWord — » );

getch() ;

CreateProcess( NULL, «WinWord», NULL, NULL, FALSE, 0,

NULL, NULL, &si, &pi ) ;

return 0 ;

}

Функция CreateThread()
— создает новый поток в адресном пространстве
процесса.

Формат функции [8]:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибуты защиты
потока

DWORD dwStackSize,

// размер стека в байтах

LPTHREAD_START_ROUTINE lpStartAddress,
//указатель на функцию потока

LPVOID lpParameter,

BDWORD dwCreationFlags,

LPDWORD lpThreadId );

// аргумент, передаваемый в функцию
потока

// флаги управления созданием потока

// область памяти для возвращения

//идентификатора потока

Функция возвращает описатель порожденного
потока. Параметры:

lpThreadAttributes — указатель на структуру,
описывающую параметры защиты потока.

Если параметру присвоено значение
NULL, то устанавливаются атрибуты “по

умолчанию”;

dwStackSize — устанавливает
размер стека, который отводится потоку.
Если параметр ра-

вен нулю, то устанавливается стек,
равный стеку первичного потока;

lpStartAddress — адрес функции, которую
будет исполнять поток. Функция имеет
один

32-битный аргумент и возвращает 32 битное
значение;

lpParameter — параметр, передаваемый в функцию,
которую будет исполнять поток;

dwCreationFlags
— дополнительный флаг, который управляет созданием потока. Если

этот параметр
равен CREATE_SUSPENDED, то поток после порождения
не запус-

кается на исполнение до вызова функции
ResumeThread;

65

lpThreadId — указатель на
32-битную переменную, которой будет присвоено значение

уникального идентификатора потока.

Пример: программа, порождающая поток

#include <stdio.h>

#include <conio.h>

#include <windows.h>

DWORD WINAPI Output( LPVOID Param )

{

while( TRUE )

{

printf( «A» ) ;

Sleep(100) ;

}

return( 0 ) ;

}

main()

{

HANDLE hThread ;

DWORD ThreadId ;

hThread = CreateThread( NULL, 0, Output, NULL, 0, &ThreadId ) ;

getch() ;

TerminateThread( hThread, 0 ) ;

return(0) ;

}

Потоки, обладающие высоким приоритетом, занимают большую часть времени

центрального
процессора, раньше завершают свою работу
и способны быстрее реагиро-

вать на
действия пользователя. Если всем потокам
будет присвоен одинаково высокий

приоритет, ничего хорошего не выйдет.
Дело в том, что если нескольким потокам
будет

присвоен один и
тот же приоритет (не имеет значения,
высокий или низкий), программа

— планировщик выделит им одинаковое
время работы центрального процессора,
и сама

идея приоритетов
утратит смысл. Один поток сможет
быстрее реагировать сигналы на

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

равной степени
и применимо и к процессом. Старайтесь
ограничивать приоритет всех

потоков и процессов
низким или средним уровнем и присваивайте
им высоких приори-

тет только по мере необходимости [8, 12].

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

BOOL SetThreadPriority(

HANDLE hThread
// дескриптор потока

int iPriority );
// новый уровень приоритета

int GetThreadPriority ( HANDLE hThread );

Функция SetThreadPriority
возвращает значение TRUE
в случае успешного завер-

шения потока, а значение FALSE
-при возникновении ошибки. Функция GetThread-

Priority возвращает значение, определяющее приоритет. Для обозначения возможных

значений приоритета в обеих функциях
используется набор констант.

66

THREAD_PRIORITY_LOWEST

са

На два уровня ниже приоритета процес-

THREAD_PRIORITY_BELOW_NORMALНа один уровень ниже
приоритета про-

цесса

THREAD_PRIORITY_NORMAL

цесса

THREAD_PRIORITY_ABOVE_NORMAL

цесса

THREAD_PRIORITY_HIGHEST

са

THREAD_PRIORITY_TIME_CRITICAL

ских процессов)

THREAD_PRIORITY_IDLE

ских процессов)

Тот же уровень приоритета, что и у про-

На один уровень выше приоритета про-

На два уровня выше приоритета процес-

Уровень 15 (для обычных пользователь-

Уровень 1 (для обычных пользователь-

Прерванный поток приостанавливает
свое выполнение и не учитывается при
рас-

пределении времени
центрального процессора. Поток остается
в таком состоянии до тех

пор, пока другой
поток не возобновит его выполнение.
Остановку потока можно произ-

вести, в частности,
в том случае, если пользователь прерывает выполнение
определен-

ной задачи. До тех
пор, пока задание не будет отменено,
поток можно перевести в со-

стояние ожидания. Если пользователь решит продолжить работу, поток возобновит

выполнение с той
точки, где он был остановлен. Для
приостановки и возобновления вы-

полнения потоков служат функции

DWORD SuspendThread ( HANDLE hThread ) ;

DWORD ResumeThread( HANDLE hThread );

Один и тот же
поток можно последовательно остановить
несколько раз, не возоб-

новляя его выполнения, однако каждой последовательной команде SuspendThread

должна соответствовать ответная команда
ResumeThread.
Система отчитывает количе-

ство отмененных команд с помощью счетчика прерываний.
Каждая команда Suspend-

Thread
инкрементирует значения счетчика, а
каждая команда ResumeThread
декремен-

тирует его. Обе
функции возвращают предыдущее значение
счетчика в виде параметра

типа DWORD.
Поток возобновит свое выполнение только
в том случае, если счетчик

примет значение 0.

Поток способен остановить
себя, но он не в состоянии самостоятельно
возобновить

свое выполнение.
Однако он может на нужное время перенести
себя в режим ожидание.

Команда
Sleep задерживает выполнения потока, удаляя его из очереди программы-

планировщика до
тех пор, пока не пройдет заданный
интервал времени. Интерактивные

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

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

режима ожидания
предпочтительнее задействования
«пустого» цикла, поскольку в этом

случае не используется время центрального
процессора.

Для осуществления паузы в течение заданного времени поток вызывает следую-

щие функции:

VOID Sleep ( DWORD dwMilliseconds ) ;

DWORD SleepEx(DWORD dwMilliseconds,

BOOL bAlertable );

// продолжительность паузы

// TRUE — возобновить работу

// при завершении операции ввода/вывода

67

Расширенная функция SleepEx обычно работает
совместно с функциями фонового

ввода/вывода и
может использоваться для инициации
команд чтения или записи, не тре-

буя их завершения.
Эти операции выполняются в фоновом
режиме. По завершении опе-

рации система извещает об этом пользователя, обращаясь к предусмотренной в про-

грамме процедуре обратного вызова. Фоновый ввод/вывод
(или перекрывающийся

ввод/вывод
далее будет рассмотрен более подробно)
чаще всего применяется в интерак-

тивных программах,
которые должны реагировать на команды
пользователя, не преры-

вая работы со сравнительно медленными устройствами, например с накопителем на

магнитной ленте или с сетевым диском.

Параметр bAlertable
функции SleepEx имеет тип Boolean. Если этот
параметр равен

TRUE, система может преждевременно возобновить выполнение потока при условии,

что перекрывающаяся
операция ввода/вывода завершилась до
истечения заданного вре-

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

WAIT_IO_COMPLETION, по истечении указанного
времени — значение 0.

По специальному запросу поток возвращает свои дескриптор и идентификатор.

Указанные ниже функции позволяют
получить информацию о текущем потоке:

DWORD GetCurrentThreadId( VOID ) ;

HANDLE GetCurrentThread( VOID );

Результирующее
значение функции GetCurrentThreadId совпадает
со значением па-

раметра lpIDThread
после выполнения функции CreateThread и
однозначно идентифици-

рует поток в
системе. Хотя идентификатор потока
нужен лишь для незначительного ко-

личества функций
Win32 API, он может использоваться с целью мониторинга

системных потоков
без необходимости поддерживать открытый
дескриптор для каждого

потока. Открытый дескриптор защищает
поток от уничтожения.

Дескриптор, полученный в результате выполнения функции
GetCurrentThread,

служит для тех же целей, что и дескриптор, возвращенный функцией
CreateThread. И

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

мом деле этот параметр является псевдодескриптором. Псевдодескриптор
— это специ-

альная константа,
которая всегда интерпретируется системой
особым образом, подобно

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

this в C++ определяет
текущий объект. Константа — псевдодескриптор,
полученная в ре-

зультате выполнения
функции GetCurrentThread, указывает на текущий
поток. В отличие

от настоящих
дескрипторов, псевдодескриптор не может
передаваться другим потокам.

Чтобы получить настоящий переносимый дескриптор потока, необходимо выполнить

следующие действия:

HANDLE hThread;

hThread = DuplicateHandle(

GetCurrentProcess(),

GetCurrentThread(),

GetCurrentProcess(),

&hThread,

0,

FALSE,

DUPLICATE_SAME_ACCESS );

68

// процесс-источник

// исходный дескриптор

// целевой процесс

// новый дублирующийся дескриптор

//привилегии доступа (подавляемые

// последним параметром)

// дочерние объекты не унаследуют

// дескриптор

// привилегии доступа копируются у

// исходного дескриптора

Хотя функция CloseHandle не влияет на
псевдодескрипторы, дескриптор, созданный с

помощью функции
DuplicateHandle, является настоящим и в конце
концов должен быть

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

GetCurrentThread, поскольку в этом случае подразумевается, что поток имеет полный

доступ сам к себе, и функция возвращает
результат, не заботясь о мерах безопасности.

По аналогии с тем, как
Windows-программа завершается по достижении конца

функции WinMain, поток
обычно прекращает свое существование
при достижении кон-

ца функции, в
которой был начат. Когда он достигает
конца стартовой функции, система

автоматически вызывает команду
ExitThread, имеющую такой синтаксис:

VOID ExitThread( DWORD dwExitCode );

Хотя операционная
система вызывает функцию ExitThread
автоматически, при не-

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

разом:

DWORD ThreadFunction( LPDWORD lpdwParam )

{

HANDLE hThread = CreateThread( <параметры>);

// далее следуют стандартные операции
инициализации;

// проверка наличия ошибочных условий

if ( <условие возникновения ошибки> )

{

ExitThread( ERROR_CODE ); // прекратить работу потока

}

// ошибки нет, работа продолжается

return( SUCCESS_CODE
);
// эта строка
программы

// заставляет систему вызвать функцию
ExitThread

}

Параметры ERROR_CODE
и SUCCESS_CODE определяются по вашему усмотре-

нию. В нашем простом примере поток
нетрудно прервать с помощью команды
return:

if( <условие возникновения ошибки> )

{

return( ERROR_CODE ); // прекратить работу
потока

}

В данном случае,
команда return приводит к тому же результату,
что и функция Ex-

itThread, так как при ее выполнении осуществляется неявный вызов последней. Эта

функция особенно полезна при необходимости
прервать поток из любой под програм-

мы, вызываемой внутри функции типа
ThreadFunction.

Когда поток
завершается с помощью оператора return,
32-разрядный код заверше-

ния
автоматически передается функции
ExitThread. После прекращения работы потока

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

// один поток вызывает эту функцию для
получения кода завершения другого
потока

BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpdwExitCode );

Функция
GetExitCodeThread возвращает значение FALSE в том
случае, если опре-

делить код завершения помешала ошибка.

69

Независимо от того, как — явно или неявно
(в результате выполнения оператора re-

turn) — вызывается функция
ExitThread, она удаляет поток из очереди программы-

планировщика и
уничтожает его стек. Однако сам объект
при этом сохраняется. Поэто-

му даже после
прекращения выполнения потока вы можете
запросить его код заверше-

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

CloseHandle), с тем чтобы поток не
занимал лишний объем памяти. При
закрытии по-

следнего дескриптора система автоматически уничтожает поток. Система не может

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

случае поток
будет уничтожен сразу же после завершения
выполнения. Если по завер-

шении
процесса остаются незакрытые дескрипторы,
система закрывает их автоматиче-

ски и удаляет все
«подвешенные» объекты, которые не
принадлежат ни одному процес-

су.

С помощью команды
ExitThread поток может остановить
себя самостоятельно в

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

усмотрению мгновенно остановить другой
поток.

// с помощью вызова этой функции один
поток может остановить другой

BOOL TerminateThread ( HANDLE hThread, DWORD
dwExitCode );

Поток не в состоянии
защитить себя от прерывания. Имея
соответствующий деск-

риптор, любой
объект может мгновенно остановить поток
вне зависимости от его теку-

щего состояния
(конечно, в том случае; если дескриптор
разрешает полный доступ к по-

току). Если при вызове функции
CreateThread использовать набор атрибутов

безопасности,
заданный по умолчанию, то результирующий
дескриптор обеспечит пол-

ные привилегии доступа к созданному
потоку.

Функция TerminateThread не уничтожает
стек потока, а только возвращает код
его

завершения. Функции
ExitThread и TerminateThread переводят объект в сигнальное со-

стояние, что служит признаком возможности
запуска других потоков, ожидавших его

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

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

рипторы.

2.2.3.
Синхронизация
потоков

При работе с
потоками необходимо иметь возможность
координировать их дейст-

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

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

нового приоритета, Win32 API содержит
функции, которые переводят потоки в
режим

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

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

частности семафоров и исключающих
семафоров.

Лучше всего проиллюстрировать применение
синхронизирующих объектов можно

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

щенных команд можно организовать ожидание сигналов от процессов,
семафоров, ис-

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

ожидает поступления сигнала от указанного
объекта:

DWORD WaitForSingleObject( HANDLE hObject,

DWORD dwMilliseconds );

70

// объект, сигнал от

// которого ожидается

// максимальное время ожидания

Функция WaitForSingleObject позволяет приостановить
выполнение потока до тех

пор, пока не поступит
сигнал от заданного объекта. Кроме того,
в этой команде указыва-

ется максимальное
время ожидания. Чтобы обеспечить
бесконечное ожидание, в качест-

ве временного интервала следует задать
значение INFINITE. Если объект уже доступен

или если он
подает сигнал в течение заданного времени,
функция WaitForSingleObject

возвращает значение
0 и выполнение потока возобновляется.
Но если заданный интер-

вал времени прошел, а объект не подал сигнала, функция возвращает значение

WAIT_TIMEOUT.

Для того чтобы заставить поток ожидать сигналы
сразу от нескольких объектов,

воспользуйтесь функцией
WaitForMultipleObjects. Функция возвратит управление
пото-

ку при поступлении
сигнала либо от одного из указанных
объектов, либо от всех объек-

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

DWORD WaitForMultipleObjects(

DWORD dwNumObjects,

LPHANDLE lpHandles,

BOOL bWaitAll,

DWORD dwMilliseconds );

// количество ожидаемых объектов

// массив дескрипторов

// TRUE — ожидание сигналов

// сразу от всех объектов;

// FALSE — ожидание сигнала от

// любого из объектов

// максимальный период ожидания

Результирующее значение WAIT_TIMEOUT,
опять-таки, говорит о том, что задан-

ный интервал
времени прошел, а сигнал от объектов
не поступил. Если флаг bWaitAll

имеет значение FALSE, соответствующее
ожиданию сигнала от любого из указанных

объектов,
в случае успешного завершения функция
WaitForMultipleObjects возвращает

код, который указывает, от какого из элементов массива
lpHandles поступил сигнал.

(Первый элемент
массива соответствует значению 0, второй
— значению 1 и т.д.). Если

флаг bWaitАll имеет значение TRUE, функция
не возвращает результат до тех пор,
пока

не
будут установлены флаги всех объектов
(т.е. пока не завершите выполнение всех
по-

токов).

Две расширенные
версии функций ожидания содержат
дополнительный флаг ста-

туса оповещения, который позволяет возобновить выполнение потока, если в течение

периода ожидания были завершены асинхронные
операции чтения или записи. Работу

этих функций
можно представить так, как будто они
просят «разбудить» их в одном из

трех случаев: если
становится доступным указанный объект,
если заканчивается задан-

ный период времени или если завершилось выполнение фоновой операции вво-

да/вывода.

DWORD WaitForSingleObjectEx (

HANDLE hObject,

DWORD dwMilliseconds,

BOOL bAlertable );

DWORD WaitForMultipleObjectsEx(

DWORD dwNumObjects,

LPHANDLE lpHandles,

BOOL bWaitAll,

// объект, сигнал от которого ожидается

// максимальное время ожидания

// TRUE — прекращение ожидания

// при завершении операции ввода/вывода

// количество ожидаемых объектов

// массив дескрипторов

// TRUE — ожидание сигналов

// сразу от всех объектов;

// FALSE — ожидание сигнала от

71

DWORD dwMilliseconds,

BOOL bAlertable );

// любого из объектов

// максимальный период ожидания

// TRUE — прекращение ожидания

// при завершении операции ввода/вывода

При успешном выполнении функции ожидания
объект, сигнал от которого ожи-

дался, обычно
определенным образом изменяется.
Например, если поток ожидал и по-

лучил сигнал от исключающего
семафора, функция восстанавливает несигнальное со-

стояние исключающего
семафора, чтобы остальные потоки знали о том, что он
занят.

Кроме того, функции
ожидания декрементируют значение
счетчика семафора и сбрасы-

вают информацию о некоторых событиях.

Функции ожидания
не изменяют состояния указанного
объекта до тех пор, пока не

поступит сигнал
от одного или нескольких других объектов.
В частности, поток не за-

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

ет сигналов от других объектов. Кроме
того, в течение времени ожидания
исключающий

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

стояние ожидания.

Конечно, ожидать
поступления сигнала от объекта можно
лишь в том случае, если

этот
объект уже создан. Начнем с создания
исключающих
семафоров
и семафоров,
по-

скольку для работы
с ними существуют параллельные
API-команды, позволяющие соз-

давать и уничтожать
эти объекты, захватывать их и освобождать, а
также получать их

дескрипторы.

Функциям,
создающим исключающие
семафоры
и семафоры,
нужно указать тре-

буемые привилегии
доступа и начальные параметры создаваемого
объекта (можно также

указать его имя, но это необязательно)
[12].

HANDLE CreateMutex (

LPSECURITY_ATTRIBUTES lpsa,

сти

// необязательные атрибуты безопасно-

BOOL bInitialOwner

LPTSTR lpszMutexName )

HANDLE CreateSemaphore(

// TRUE — создатель хочет

// завладеть полученным объектом

// имя объекта

LPSECURITY_ATTRIBUTES lpsa,

//необязательные атрибуты безопасности

LONG lInitialCount,

LONG lMaxCount,

LPTSTR lpszSemName );

// исходное значение счетчика (обычно
0)

// максимальное значение

// счетчика (ограничивает число потоков)

// имя семафора (может иметь значение
NULL)

Если в качестве атрибута безопасности задано
значение NULL, результирующий

дескриптор
получит все привилегии доступа и не
будет наследоваться дочерними про-

цессами. Имена
объектов являются необязательными,
однако они становятся полезными

в ситуации, когда несколько процессов
управляют одним и тем же объектом.

Если флагу
bInitialOwner присвоить значение TRUE,
поток сразу после создания

объекта завладеет
им. Созданный исключающий семафор не
станет подавать сигналы до

тех пор, пока поток не освободит его.

В отличие от исключающего
семафора, который может принадлежать
только од-

ному потоку,
неисключающий семафор остается в
сигнальном состоянии до тех пор, по-

ка его счетчик
захватов не получит значения iMaxCount.
Если другие потоки в этот мо-

72

мент попытаются завладеть семафором, они будут приостановлены до тех пор,
пока

счетчик захватов не будет декрементирован
до значения ниже максимального.

Пока семафор (или исключающий семафор)
существует, поток взаимодействует с

ним посредством
операций захвата и освобождения. Для
захвата любого объекта поток

вызывает функцию
WaitForSingleObject (или одну из ее разновидностей).
Завершив вы-

полнение задачи, которая синхронизировалась захваченным объектом,
поток освобож-

дает этот объект с помощью одной из
следующих функций:

BOOL ReleaseMutex( HANDLE hMutex ) ;

BOOL ReleaseSemaphore(

HANDLE hSemaphore,

LONG lRelease,

LPLONG lplPrevious );

// величина, на которую

// инкрементируется значение счетчика

// при освобождении объекта (обычно 1)

// переменная, которой присваивается

// предыдущее значение счетчика

При освобождении семафора: или
исключающего семафора значение счетчика
за-

хватов инкрементируется.
Значение счетчика, превышающее
0, воспринимается систе-

мой как сигнал объекта ожидающим его
потокам.

Освободить
исключающий семафор может только тот
поток, который завладел им.

Однако любой поток
может вызвать функцию ReleaseSemaphore, которая
инкрементиру-

ет значение
счетчика захватов обычного семафора
вплоть до его максимального значе-

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

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

Обратите внимание,
что функция CreateSemaphore позволяет при
создании нового сема-

фора
присвоить его счетчику значение, меньшее
максимального. Например, при разра-

ботке
нового семафора его счетчику можно задать начальное
значение 0. Такой прием

позволит
заблокировать все потоки до тех пор,
пока программа не произведет инициали-

зацию, а затем не увеличит значение
счетчика с помощью команды ReleaseSemaphore.

Не забывайте
вовремя освобождать синхронизирующие объекты.
Не задав макси-

мального времени ожидания и забыв освободить исключающий семафор,
вы заблоки-

руете все ожидающие его потоки.

Поток может ожидать несколько сигналов
от одного и того же объекта, не будучи

заблокированным,
однако после завершения каждого из
процессов ожидания необходи-

мо, выполнять операцию освобождения. Это требование справедливо для семафоров,

исключающих семафоров и критических
разделов.

Событие
представляет собой объект, который
создается программой при необхо-

димости информировать потоки о выполнении
определенных действий. В простейшем

случае (ручной
сброс) событие переключает свое состояние
с помощью команд SetEvent

(сигнал включен) и
ResetEvent (сигнал выключен). Когда сигнал
включается, его полу-

чают все потоки,
которые ожидают появления соответствующего
события. Если сигнал

выключается, все
такие потоки блокируются. В отличие от
семафоров и исключающих

семафоров, события
данного типа изменяют свое состояние только
при подаче соответ-

ствующей команды каким-нибудь потоком.

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

только после того,
как программа обновит свое окно или пользователь введет опреде-

ленную информацию [12]. Ниже представлены
основные функции, предназначенные для

работы с событиями:

73

HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES lpsa,

BOOL bManualReset,

BOOL bInitialState,

LPTSTR lpszEventName );

BOOL SetEvent ( HANDLE hEvent );

BOOL ResetEvent( HANDLE hEvent );

// привилегии доступа

// (по умолчанию = NULL)

// TRUE — событие должно быть

// сброшено вручную

// TRUE — создание события в

// сигнальном состоянии

//имя события (допускается

// значение NULL)

При установке параметра bInitialState функция
CreateEvent создает событие, кото-

рое сразу же будет находиться в сигнальное
состоянии. Функции SetEvent и ResetEvent в

случае успешного
завершения возвращают значение TRUE, при
возникновении ошибки

— значение FALSE.

Параметр
bManualReset функции
CreateEvent позволяет создать событие, сбрасы-

ваемое не вручную, а автоматически.
Автоматически сбрасываемое событие
переходит в

несигнальное
состояние сразу же после выполнения
функции SetEvent. Для таких собы-

тий
функция ResetEvent является избыточной.
Кроме того, перед автоматическим сбро-

сом по каждому
сигналу событие освобождает только
один поток. Автоматически сбра-

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

поток подготавливает данные для других, вспомогательных потоков. При готовности

нового набора
данных основной поток устанавливает
событие, по которому освобожда-

ется один вспомогательный поток. Остальные вспомогательные потоки продолжают

ожидать подготовки новых данных.

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

вать импульсное событие:

BOOL PulseEvent( hEvent ) ;

Импульсное событие включает
сигнал на короткий промежуток времени.
Приме-

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

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

ваемого автоматически, дает возможность оповестить только один ожидающий поток.

Если не было ни
одного ожидающего потока, то никакой другой
поток не будет опове-

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

включенным до тех
пор, пока не появится ожидающий его
поток. После оповещения по-

тока событие сбрасывается автоматически.

Семафоры, исключающие семафоры и события могут совместно использоваться

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

Путем совместного
задействования синхронизирующих
объектов процессы могут коор-

динировать свои действия по аналогии
с тем, как это делают потоки. Существует
три

механизма
совместного использования. Первый из
них — это наследование, при котором

один процесс
создает новый процесс, получающий копии
всех дескрипторов родитель-

ского процесса.
Копируются только те дескрипторы,
которые при создании были поме-

чены как доступные для наследования.

Два других метода
сводятся к созданию второго дескриптора
существующего объ-

екта с помощью
вызова функций. Какая из функций будет вызвана, зависит
от имею-

щейся информации.
При наличии дескрипторов как исходного
процесса, так и процесса,

назначения следует
вызывать функцию DuplicateHandle, при наличии
только имени объ-

74

екта — одну из функций Openxxx. Две программы
могут заранее определить имя совме-

стно используемого объекта.
Кроме того, одна из программ способна передать
другой

это
имя посредством совместно используемой
области памяти функций DDEML (DDE

Management Library —
библиотека управления динамическим
обменом данных) или кана-

ла.

BOOL DuplicateHandle(

HANDLE hSourceProcess,

HANDLE hSource,

HANDLE hTargetProcess,

LPHANDLE lphTarget,

DWORD fdwAccess,

BOOL bInherit,

DWORD fdwOptions );

HANDLE OpenMutex(

DWORD fdwAccess,

BOOL binherit,

LPTSTR lpszName );

HANDLE OpenSemaphore(

DWORD fdwAccess,

BOOL bInherit,

LPTSTR lpszName );

HANDLE OpenEvent(

DWORD fdwAccess,

BOOL bInherit,

LPTSTR lpszName );

// процесс, которому
принадлежит

// исходный объект

// дескриптор исходного объекта

// процесс, который хочет создать

// копию дескриптора

// переменная для записи копии дескриптора

// запрашиваемые привилегии доступа

// может ли наследоваться копия
дескриптора?

// дополнительные операции, например

// закрытие исходного дескриптора

//запрашиваемые привилегии доступа

// TRUE — дочерний процесс может

// наследовать этот дескриптор

// имя исключающего семафора

// запрашиваемые привилегии доступа

//TRUE — дочерний процесс может

// наследовать этот дескриптор

// имя семафора

// запрашиваемые привилегии доступа

// TRUE — дочерний процесс может

// наследовать этот дескриптор

// имя события

Используемый в этом примере тип данных
LPTSTR — это обобщенный текстовый

тип, который компилируется по-разному
в зависимости от того, какой стандарт,
Unicode

или ASCII, поддерживается приложением.

Семафоры, исключающие
семафоры и объекты событий будут
сохраняться в памя-

ти до тех пор, пока
не завершатся все использующие их
процессы или пока с помощью

функции CloseHandle не будут закрыты все
дескрипторы соответствующего объекта:

BOOLCloseHandle(hObject);

Критический
раздел представляет собой
объект, выполняющий те же функции,

что и исключающий
семафор, но в отличие от последнего
критический раздел не может

наследоваться.
Оба объекта доступны только для
одного процесса. Преимущество кри-

тических разделов перед исключающими
семафорами состоит в том, что они проще
в

управлении и гораздо быстрее работают
[12].

Терминология,
принятая для функций, которые используются
при работе с крити-

ческими разделами,
отличается от терминологии,
разработанной для функций управле-

ния
семафорами, исключающими семафорами и
событиями, однако сами функции вы-

полняют одни и те же операции. В частности, принято говорить не о создании

75

критического раздела, а о
его инициализации.
Процесс не ожидает критический раздел,
а

входит в него, и
не освобождает критический раздел, а
покидает его; к тому же вы не

закрываете дескриптор, а удаляете
объект.

VOID InitializeCriticalSection ( LPCRITICAL_SECTION lpcs );

VOID EnterCriticalSection( LPCRITICAL_SECTION lpcs );

VOID LeaveCriticalSection( LPCRITICAL_SECTION lpcs );

VOID DeleteCriticalSection( LPCRlTICAL_SECTION lpcs );

Переменная типа
LPCRITICAL_SECTION содержит указатель
(а не дескриптор)

критического раздела. Функция
InitializeCriticalSection должна получить указатель на

пустой объект (&cs), который можно
создать следующим образом:

CRITICAL SECTION cs;

2.2.4.
Использование
классов MFC
для
создания
потоков

Способ создания потоков с помощью
функций библиотеки MFC, заключается в

создании
класса, порожденного от класса CWinThread.
Схема этого процесса выглядит

следующим образом:

// Класс CThreadExample

IMPLEMENT_DYNCREATE(CThreadExample, CWinThread)

CThreadExample::CThreadExample()

{

}

// инициализация переменных-членов
класса

CThreadExample::~CThreadExample()

{

}

BOOL CThreadExample::InitInstance()

{

// TODO: здесь следует выполнить инициализацию
потока

//здесь должны выполняться операции
инициализации,

//не связанные с переменными, например
создание

// экземпляров других объектов класса

return TRUE;

}

int CThreadExample::ExitInstance()

{

// TODO: здесь выполняются все операции
очистки для потока

return CWinThread::ExitInstance();

}

BEGIN_MESSAGE_MAP(CThreadExample, CWinThread)

//{{AFX_MSG_MAP(CThreadExample)

76

// ПРИМЕЧАНИЕ — Мастер ClassWizard будет
добавлять/удалять в

// этом месте макросы обработки сообщений

//}}AFX_MSG_MAP

END_MESSAGE_MAP ()

Объект класса CWinThread представляет поток
выполнения в рамках приложения.

Хотя основной поток
выполнения приложения обычно задается
объектом класса, поро-

жденного от
CWinApp, сам класс CWinApp является производным от класса

CWinThread.

Для обеспечения
безопасности потоков в MFC-приложениях
должны применяться

классы, являющиеся
производными от класса CWinThread, библиотека
MFC использует

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

не могут использовать ни одной из
API-функций библиотеки MFC.

Поддерживаются два основных типов потоков, а именно рабочие и интерфейс-

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

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

пользователем и не должны реагировать
на сообщения.

Интерфейсные потоки,
в отличие от рабочих, обрабатывают
сообщения, получен-

ные от системы
(или от пользователя). Для них необходима
специальная процедура об-

работки сообщений.
Создаются интерфейсные потоки на базе
класса CWinApp или не-

посредственно класса CWinThread.

Объект класса
CWinThread обычно существует в течение всего
времени существо-

вания потока,
однако такой способ функционирования
можно изменить, присвоив пере-

менной-члену m_bAutoDelete значение
FALSE.

Потоки создаются
с помощью функции AfxBeqinThread. Для создания
интерфейс-

ного потока функции AfxBeqinThread следует
передать указатель на класс CRuntimeC-

lass объекта, производного от класса
CWinThread. В случае рабочих потоков функция

AfxBeqinThread вызывается с указанием управляющей функции и параметра, переда-

ваемого последней.

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

параметры,
изменяющие приоритет, размер стека, флаги
создания и атрибуты безопас-

ности потока. Функция
AfxBeqinThread возвращает указатель на новый объект класса

CWinThread.

В качестве альтернативного
варианта можно определить, а затем создать объект,

производный от класса
CWinThread, вызвав функцию
CreateThread данного класса. В

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

тельных созданиях и уничтожениях потока.

77

Содержание

  1. Многозадачность в операционных системах, виды многозадачности
  2. По типу наименьшего элемента управляемого кода
  3. Процессная многозадачность.
  4. Поточная многозадачность.
  5. По способу организации времени выполнения каждого процесса
  6. Параллельная многозадачность
  7. Типы псевдопараллельной многозадачности
  8. Многозадачность в операционной системе Windows
  9. Многозадачная ОС

Многозадачность в операционных системах, виды многозадачности

Многозада́чность — свойство ОС или среды выполнения обеспечивать возможность параллельной обработки нескольких процессов. Иными словами, многозадачность — способ выполнения нескольких задач в один период времени. При этом задачи делят между собой общие ресурсы (resources sharing), помимо этого осуществляется планирование (scheduling). [1]

Система называется однозадачной,если она не обладает свойством многозадачности, т.е. задачи в ней выполняются последовательно. DOS — одноза­дачная ОС.

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

По типу наименьшего элемента управляемого кода

Процессная многозадачность.

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

Поточная многозадачность.

Многопоточность — специализированная форма многозадачности. Наименьший элемент управляемого кода — поток. Многопотоковая (multi-threaded) система предоставляет возможность одновременного выполнения одной программой 2 и более задач

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

Параллельная многозадачность

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

Типы псевдопараллельной многозадачности

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

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

Многозадачность в операционной системе Windows

ТЕОРЕТИЧЕСКОЕ ОПИСАНИЕ

Многозадачность

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

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

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

  • Переключение по событию
  • Переключение по времени

Переключение по событию

Переключение задач по событию показано на рис 1.

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

Переключение по времени

Переключение задач по времени показано на рис 2.

Рис 2. Переключение задач по времени.

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

Многозадачность в операционной системе Windows

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

1. Прерывание от таймера. Это означает, что время, предоставленное активной задаче, истекло. Планировщик прекращает ее выполнение и передает управление задаче с наибольшим приоритетом. Такое переключение происходит наиболее часто.

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

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

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

В Windows каждая запущенная 32- х битовая программа называется процессом. Процесс в основном имеет дело с распределением ресурсов системы. Исполняемый код для системы является другим объектом, называемым нитью, или потоком управления (thread). Когда запускается новый процесс, ему автоматически придается одна нить. Нити (потоки) используются операционной системой Windows для диспетчеризации времени процессора. Диспетчеризация — это метод выделения времени каждой из нитей (не процессов, поскольку процесс может иметь несколько нитей). Операционная система рассматривает все готовые к запуску потоки и выбирает для выполнения один из них. Диспетчер также определяет квант времени, предоставляемый для выполнения каждому из потоков.

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

ОПИСАНИЕ ЛАБОРАТОРНОЙ РАБОТЫ

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

Многозадачная ОС

Многозадачные операционные системы

Почти все современные операционные системы (Windows 95, Windows NT, Windows 2000, Unix) поддерживают преимущественную многозадачность Этот термин, который часто переводят как вытесняющая многозадачность, означает, что процесс или, точнее, его поток, который в данный момент активен, имеет преимущество перед другими конкурирующими потоками с одинаковым приоритетом. Системы Windows 3.1 и Macintosh поддерживают кооперативную многозадачность в которой все управление отдано системе. В такой системе легче программировать, но она менее эффективна.

Основным признаком многозадачной ОС является способность совмещать выполнение нескольких прикладных программ. Большое значение при этом имеет способ совмещения, то есть на каком уровне или как конкретно реализовано совмещение. Если однопроцессорная, но многозадачная, система выделяет каждой прикладной программе определенный квант времени спустя который она переключается на выполнение следующей программы, то это система с разделением времени Системы с разделением времени появились в начале 60-х. Они управлялись main /rame-компьютерами, обслуживающими многочисленные удаленные терминалы. В качестве терминалов сначала использовались обычные телетайпы, которые умели только вводить или выводить информацию. Благодаря огромной разнице в скорости работы таких устройств, как телетайп и процессор, системы с разделением времени успевали переключаться между многими терминалами и вводить или выводить информацию так, что каждому пользователю казалось, что он единолично управляет удаленным процессором. Затем появились персональные компьютеры, которые стали использоваться в качестве удаленных терминалов. В связи с этим для операционной системы главного процессора (например, IBM-370) отпала необходимость заниматься посимвольным вводом-выводом. Теперь акцент в разработке операционных систем был перенесен на управление выполняемыми программными модулями, принадлежащими разным пользователям и одновременно находящимися в памяти главного компьютера. Появились такие понятия, как очередь заданий •— очередь на обслуживание каким-либо устройством: принтером, плоттером, накопителем на магнитном носителе, приоритет задания, ожидаемое время завершения задания и т. д.

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

Первые операционные системы, реализованные на персональных компьютерах, сильно уступали в концептуальном плане и по своим реальным возможностям системам с разделением времени, давно реализованным в mainframe- компьютерах. В Win 16, например, тоже существует понятие многозадачности. Реализовано оно следующим образом: обработав очередное сообщение, приложение передает управление операционной системе, которая может передать управление другому приложению. Такой вид многозадачности, при котором операционная система передает управление от одного приложения другому не в любой момент времени, а только когда текущее приложение отдает управление системе, получил, как было упомянуто, название кооперативной многозадачности (cooperative multi-tasking).

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

В Windows начиная с Windows 95 реализован принципиально другой вид многозадачности, в котором операционная система действительно контролирует и управляет процессами, потоками и их переключением. Способность операционной системы прервать выполняемый поток практически в любой момент времени и передать управление другому ожидающему потоку определяется термином preemptive multitasking — преимущественная, или вытесняющая, многозадачность. Реализация ее выглядит так: все существующие в данный момент потоки, часть из которых может принадлежать одному и тому же процессу, претендуют на процессорное время и, с точки зрения пользователя должны выполняться одновременно. Для создания этой иллюзии система через определенные промежутки времени забирает управление, анализирует свою очередь сообщений, распределяет сообщения по другим очередям в пространстве процессов и, если считает нужным, переключает потоки (рис. 12.5).

Реализация вытесняющей многозадачности в Windows 2000 дает не только возможность плавного переключения задач, но и устойчивость среды к зависаниям, так как ни одно приложение не может получить неограниченные права на процессорное время и другие ресурсы. Так система создает эффект одновременного выполнения нескольких приложений. Если компьютер имеет несколько процессоров, то системы Windows NT/2000 могут действительно совмещать выполнение нескольких приложений. Если процессор один, то совмещение остается иллюзией. Когда заканчивается квант времени, отведенный текущей программе, система ее прерывает, сохраняет контекст и отдает управление другой программе, которая ждет своей очереди. Величина кванта времени (time slice)зависит от ОС и типа процессора, в Windows NT она в среднем равна 20 мс. Следует отметить, что добиться действительно одновременного выполнения потоков можно только на машине с несколькими процессорами и только под управлением Windows NT/2000, ядра которых поддерживают распределение потоков между процессорами и процессорного времени между потоками на каждом процессоре. Windows 95 работает только с одним процессором. Даже если у компьютера несколько процессоров, под управлением Windows 95 задействован лишь один из них, а остальные простаивают.

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

Многозадачность в Windows

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

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

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

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

Основные понятия

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

  • Мультипроцессирование — использование нескольких процессоров для одновременного выполнения задач.
  • Мультипрограммирование — одновременное выполнение нескольких задач на одном или нескольких процессорах.

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

Мультипроцессирование

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

Разные подходы к реализации мультипроцессирования

Рис.
6.1.
Разные подходы к реализации мультипроцессирования

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

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

  • наиболее массовыми являются так называемые SMP (Shared Memory Processor или Symmetric MultiProcessor) машины. В таких компьютерах несколько процессоров подключены к общей оперативной памяти и имеют к ней равноправный и конкурентный доступ (см. рис. 6.2). По мере увеличения числа процессоров производительность оперативной памяти и коммутаторов, связывающих процессоры с памятью, становится критически важной. Обычно в SMP используются 2-8 процессоров; реже число процессоров достигает десятков. Взаимодействие одновременно выполняющихся процессов осуществляется посредством использования общей памяти, к которой имеют равноправный доступ все процессоры.

    SMP компьютер

    Рис.
    6.2.
    SMP компьютер

  • при необходимости создания систем с качественно большим числом процессоров прибегают к MPP (Massively Parallel Processors) системам. Для этого используют несколько однопроцессорных или SMP-систем, объединяемых с помощью некоторого коммуникационного оборудования в единую сеть (см. рис. 6.3). При этом может применяться как специализированная высокопроизводительная среда передачи данных, так и обычные сетевые средства — типа Ethernet. В MPP системах оперативная память каждого узла обычно изолирована от других узлов, и для обмена данными требуется специально организованная пересылка данных по сети. Для MPP систем критической становится среда передачи данных; однако в случае мало связанных между собой процессов возможно одновременное использование большого числа процессоров. Число процессоров в MPP системах может измеряться сотнями и тысячами.

    MPP система

    Рис.
    6.3.
    MPP система

  • иногда используют так называемые NUMA и cc-NUMA архитектуры; они являются компромиссом между SMP и MPP системами: оперативная память является общей и разделяемой между всеми процессорами, но при этом память неоднородна по времени доступа. Каждый процессорный узел имеет некоторый объем оперативной памяти, доступ к которой осуществляется максимально быстро; для доступа к памяти другого узла потребуется значительно больше времени (см. рис. 6.4). cc-NUMA отличается от NUMA тем, что в ней на аппаратном уровне решены вопросы когерентности кэш-памяти (cache-coherent) различных процессоров. Формально на NUMA системах могут работать обычные операционные системы, созданные для SMP систем, хотя для обеспечения высокой производительности приходится решать нетипичные для SMP задачи оптимального размещения данных и планирования с учетом неоднородности памяти.

    NUMA или cc-NUMA система

    Рис.
    6.4.
    NUMA или cc-NUMA система

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

Windows содержит встроенные механизмы, необходимые для работы на SMP; также возможна установка этой ОС на cc-NUMA системах (современные версии Windows имеют механизмы поддержки cc-NUMA систем). Специальных, встроенных в ОС средств для исполнения приложений на MPP системах в Windows не предусмотрено. Windows предполагает альтернативное применение MPP систем, построенных на обычных сетях, для реализации web- или файловых серверов с балансировкой нагрузки по узлам кластера.

Мультипрограммирование

Мультипрограммирование (то есть одновременное выполнение разного кода на одном или нескольких процессорах) возможно и без реального мультипроцессирования. Конечно, при наличии только одного процессора должен существовать некоторый механизм, обеспечивающий переключение процессора между разными выполняемыми потоками. Такой режим разделения процессорного времени позволяет одному процессору обслуживать несколько задач «как бы одновременно»: осуществляя быстрое переключение между разными задачами и выполняя в данный момент времени код только одной задачи, процессор создает иллюзию одновременного выполнения кода разных задач. Более того, даже на многопроцессорных системах при реальной возможности распараллеливания задач по разным процессорам, обычно используют механизм разделения времени на каждом из доступных процессоров. Формально мультипрограммирование предполагает именно разделение процессорного времени, поэтому иногда его противопоставляют мультипроцессированию: реализация многозадачности на одном процессоре в противовес использованию многих процессоров.

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

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

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

Планирование задач

Рис.
6.5.
Планирование задач

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

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

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

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

Граф состояния задачи

Рис.
6.6.
Граф состояния задачи

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

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

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

Характерный пример невытесняющей многозадачности — 16-ти разрядные Windows (включая собственно 16-ти разрядные версии Windows, выполнение 16-ти разрядных приложений в Windows-95, 98, ME и выполнение 16-ти разрядных приложений в рамках одной Windows-машины в NT, 2000, XP и 2003). В таких приложениях операционная система не прерывает выполнение текущей задачи до вызова ею функций типа GetMessage или WaitMessage, во время которых Windows осуществляет при необходимости переключение на другую задачу.

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

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

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

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

Моменты перепланирования задач

Рис.
6.7.
Моменты перепланирования задач

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

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

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

Реализации Windows NT, 2000, XP, 2003+ предусматривают достаточно развитый и сложный планировщик, учитывающий множество факторов и корректирующий как назначение и длительность отводимых задаче квантов, так и приоритеты задач. При этом планировщик является настраиваемым, и его логика работы несколько отличается в зависимости от настроек системы (некоторые доступны через панель управления) и от назначения системы (работа планировщика различна у серверов и рабочих станций).

Важно отметить, что Windows является гибкой системой разделения времени с вытесняющей многозадачностью и не может рассматриваться в качестве системы реального времени. Даже те процессы, которые с точки зрения Windows относятся к классу процессов так называемого «реального времени», на самом деле требованиям, предъявляемым к системам реального времени, не удовлетворяют. Такие процессы получат приоритетное распределение процессорного времени и будут обрабатываться планировщиком с учетом их «особого статуса»; однако при этом нельзя гарантировать строгого выполнения временных ограничений. Более того, в силу используемых механизмов управления памятью, нельзя точно предсказать время, необходимое для выполнения той или иной операции. В любой момент времени при самом невинном обращении к какой-либо переменной или функции может потребоваться обработка ошибок доступа, подкачка выгруженных страниц, освобождение памяти и т.д. — то есть действия, время завершения которых предсказать крайне трудно. Фактически можно давать лишь вероятностные прогнозы по времени выполнения той или иной операции. До определенных рамок Windows можно применять в мягких системах реального времени — с достаточно свободными ограничениями, но даже незначительная вероятность превышения временных ограничений иногда просто недопустима.

Базовая терминология

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

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

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

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

В Windows для обозначения этих понятий использованы термины process (процесс), thread (поток) и fiber (волокно). Достаточно часто термин «thread» переводится на русский язык как «нить», а не «поток». Термин «fiber» также может переводиться либо как «нить», либо как «волокно». Поток соответствует потоку ядра и планируется ядром операционной системы, а волокно соответствует потоку пользователя и планируется в приложении пользователя.

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

Марат Хайрулин, эксперт Microsoft в России, продолжает исследовать нюансы работы с несколькими задачами и рассказывает о совмещении окон и разделении экрана, о вашей личной машине времени для сайтов и документов, и о реальной пользе виртуальных столов.

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

Переключение по-старому и по-новому

Переключение между приложениями – наверное то, что большинство из нас делает «на автомате», и никого, конечно, не удивит сочетание клавиш Alt + Tab. Но если одновременно нажать также и Ctrl (то есть Ctrl + Alt + Tab), то эта комбинация зафиксирует меню со всеми открытыми окнами на экране и позволит выбрать нужное приложение одним кликом мыши или касанием пальца (выбрать окно можно также с помощью стрелок на клавиатуре, а открыть – с помощью Enter). Может быть полезно, когда у вас открыто много окон.

Чуть менее известное, но тоже классическое сочетание клавиш Windows + Tab дает больше возможностей, чем кажется на первый взгляд.

Нажимая эти клавиши в актуальных версиях Windows 10, мы попадаем в раздел «Представление задач». Здесь можно не только переключаться между приложениями, но и воспользоваться «Временной шкалой» и «Виртуальными рабочими столами». К слову, вместо горячих клавиш вы можете кликнуть по кнопке «Представление задач» (обычно она расположена рядом с кнопкой «Пуск») или провести пальцем от левого края к центру сенсорного экрана. Кстати, если у вас современный ноутбук – попробуйте жест для тачпада: проведите по нему тремя пальцами вверх.


Режим Представление задач

«Временная шкала»

«Временная шкала» появилась в Windows 10 два года назад. Она помогает вернуться к задачам, над которыми вы работали ранее на вашем компьютере. При необходимости вы также сможете синхронизировать ее и с другими устройствами с вашей учетной записью*.

Для меня «Временная шкала» стала своеобразной машиной времени. Работа над многими проектами длится несколько дней. И если, допустим, в прошлую пятницу я работал с определенными сайтами и документами, вернувшись к этому проекту в среду, я смогу легко восстановить картину. Я просто отмотаю шкалу до нужной даты – той самой пятницы, увижу и смогу открыть те самые сайты и документы, в которые я тогда был погружен.


Поиск на Временной шкале

Поиск на «Временной шкале» тоже не раз меня выручал. В отличие от обычного поиска по файлам, я смогу искать не среди всех документов на устройстве (а их может быть очень много), а именно среди тех, с которыми я работал в последние дни. Возможно, вам знакомо сочетание Ctrl + F, запускающее поиск в Проводнике и во многих приложениях. Эта комбинация сработает и на экране «Представление задач»: то есть можно нажать сначала Windows + Tab, а затем – Ctrl + F и ввести искомое слово для поиска по «Временной шкале».

* Подробная справка по настройкам «Временной шкалы».

Виртуальные рабочие столы Windows 10

Концепция виртуальных рабочих столов далеко не нова. Если говорить о Windows, то одним из вариантов их использования была утилита Desktops, которую когда-то (последняя версия вышла в 2012 году) разработал Марк Руссинович. В Windows 10 виртуальные рабочие столы встроены в систему и помогают разделять потоки задач, переключаться между ними.

Если раньше вы не работали с виртуальными столами, для понимания их логики представьте такую аналогию: вам доступно несколько мониторов, на каждом вы можете открыть нужные программы, разделив их по рабочим потокам, например: на одном мониторе – работа с почтой и календарем, на другом – работа с несколькими документами Word, а на третьем – работа с браузером и OneNote. В каждый момент вы смотрите только на один монитор (виртуальный рабочий стол) со своим набором приложений. А переключаясь между виртуальными столами, вы как будто переводите взгляд с одного монитора на другой.


Перетаскивание окна для переноса его на новый виртуальный рабочий стол

Создать новый виртуальный рабочий стол можно на экране «Представление задач»: нажмите Windows + Tab и перетащите нужные окна открытых приложений на поле с надписью «+ Создать рабочий стол», и они будут перемещены на другой виртуальный рабочий стол. Можно также создать новый, пустой виртуальный стол (Windows + Ctrl + D) и уже затем открыть на нем нужные программы.

«Переводить взгляд» (то есть переключаться между настроенными рабочими столами) можно, выбирая нужный стол на экране «Представление задач», но намного удобнее переключаться с помощью горячих клавиш: Windows + Ctrl + стрелки вправо/влево, а на современных тачпадах – 4 пальца влево или вправо.

Полезные решения для работы с несколькими приложениями

Теперь еще об одной повседневной необходимости – работе с несколькими приложениями одновременно.

Разделение экрана

Первой возможности, о которой хочу напомнить, уже много лет, и в первоначальном виде (под названием Aero Snap) она появилась еще в Windows 7. В Windows 10 ее возможности расширили и назвали Snap Assist. Речь про разделение экрана для закрепления двух (а в Windows 10 – до четырех) приложений.


Snap Assist предлагает выбрать второе окно для закрепления справа

Чтобы это сделать, нужно взять приложение за самую верхнюю полоску, поднести его к правой или левой границе экрана до появления на экране его «тени» и отпустить (тем самым, закрепив первое приложение), а затем в появившихся рядом миниатюрах других приложений выбрать второе для закрепления рядом.  Сценарий несложный, работает и для мыши, и для пальца. Еще проще это можно сделать с помощью сочетания клавиш Windows + клавиши со стрелками вправо/влево. Этому сочетанию уже больше 10 лет, но у тех, кто применяет его впервые, и сейчас порой возникает ощущение «цифровой магии».

Любознательным пользователям также напомню, что в Windows 10 можно отправлять приложение в «четвертинку» экрана, перенеся его в угол (или используя дополнительно клавиши Windows + стрелки вверх/вниз). При закреплении двух приложений можно перемещать границу между ними, выделяя какому-то из приложений больше места. Чтобы выбрать приложения для закрепления на экране, можно кликнуть правой кнопкой мыши по их миниатюрам на экране «Представление задач».

Окно поверх

У меня было довольно мало ситуаций, когда требовалось закреплять окно одного приложения поверх другого (кажется, на телевизорах подобное называлось режимом «картинка в картинке»), но если у вас такая необходимость возникает, напомню в завершение заметки о двух небольших возможностях.

Мини-режим встроенного видеоплеера (приложение «Кино и ТВ», которое воспроизводит видео в Windows 10 по умолчанию). Запустите видео и нажмите на небольшую кнопку в правом нижнем углу (Воспроизвести в мини-режиме), окно с видеороликом будет размещено поверх всех окон.


Видео в режиме Окно поверх

Аналогичную возможность, только с закреплением поверх всех приложений окна браузера, можно получить с использованием отдельных утилит. Однажды мне потребовалось работать над документом, постоянно сверяясь при этом с сайтом одного онлайн-сервиса, и меня выручило приложение Always on Top, доступное в Microsoft Store. Оно встраивается в меню «Поделиться» в Edge и позволяет отправить любой сайт в окно, расположенное поверх всех приложений. Я мог бы пошутить, что этот вариант отлично подошел бы для просмотра каналов на YouTube «одним глазком» во время работы, например, над сводными таблицами в Excel. Но как мы и обсуждали в первой заметке, такая многозадачность скорее повредит и просмотру, и работе.

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

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

Сколько из лайфхаков вы использовали?


46.15%
2-3. И они пригождаются
42


9.89%
Ни одного (и теперь это в прошлом)
9


34.07%
Сижу на Linux/MacOS
31

Проголосовал 91 пользователь.

Воздержались 9 пользователей.

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 10:47, 5 июня 2019.

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

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

Сущусвуют однозадачные системы, которые не обладают свойством многозадачности, т.е. в такой ОС задачи исполняются последовательно.[Источник 1]

Содержание

  • 1 Свойства многозадачной среды
  • 2 Трудности реализации многозадачной среды
  • 3 История многозадачных операционных систем
  • 4 Классификация
    • 4.1 По типу наименьшего элемента управляемого кода
      • 4.1.1 Процессная многозадачность.
      • 4.1.2 Поточная многозадачность.
    • 4.2 По способу организации времени выполнения каждого процесса
      • 4.2.1 Параллельная многозадачность
      • 4.2.2 Типы псевдопараллельной многозадачности
        • 4.2.2.1 Невытесняющая многозадачность
        • 4.2.2.2 Совместная или кооперативная многозадачность
        • 4.2.2.3 Вытесняющая, или приоритетная, многозадачность (режим реального времени)
  • 5 Диспетчеризация
    • 5.1 Состояние задачи
    • 5.2 Стратегии диспетчеризации
  • 6 Программная реализация многозадачности
  • 7 Критические разделы
  • 8 Использование событий
  • 9 Проблемные ситуации в многозадачных системах
    • 9.1 Голодание (starvation)
    • 9.2 Гонка (race condition)
    • 9.3 Инверсия приоритета
  • 10 Процессы в Windows и потоковая многозадачность
  • 11 Многозадачность в Linux
    • 11.1 Использование getpid() и getppid()
  • 12 Источники

Свойства многозадачной среды

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

Более развитые многозадачные системы проводят распределение ресурсов динамически, когда задача стартует в памяти или покидает память в зависимости от её приоритета и от стратегии системы. Такая многозадачная среда обладает следующими особенностями:

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

Трудности реализации многозадачной среды

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

Кроме надёжности, многозадачная среда должна быть эффективной. Затраты ресурсов на её поддержание не должны: мешать процессам проходить, замедлять их работу, резко ограничивать память.[Источник 1]

История многозадачных операционных систем

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

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

Впервые многозадачность операционной системы была реализована в ходе разработки операционной системы Multics (1964 год). Одной из первых многозадачных систем была OS/360 (1966), используемая для компьютеров фирмы IBM и их советских аналогов ЕС ЭВМ. Разработки системы были сильно затянуты, и на начальное время фирма IBM выдвинула однозадачный DOS, чтобы удовлетворить заказчиков до полной сдачи OS/360 в эксплуатацию. Система подвергалась критике по причине малой надёжности и трудности эксплуатации.

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

На компьютерах PDP-11 и их советских аналогах СМ-4 использовалась многозадачная система RSX-11 (советский аналог — ОСРВ СМ ЭВМ), и система распределения времени TSX-PLUS, обеспечивающая ограниченные возможности многозадачности и многопользовательский режим разделения времени, эмулируя для каждого пользователя однозадачную RT-11(советский аналог — РАФОС). Последнее решение было весьма популярно из-за низкой эффективности и надёжности полноценной многозадачной системы.

Аккуратным решением оказалась операционная система VMS, разработанная первоначально для компьютеров VAX (советский аналог — СМ-1700) как развитие RSX-11.

Первый в мире мультимедийный персональный компьютер Amiga 1000 (1984 год) изначально проектировался с расчётом на полную аппаратную поддержку вытесняющей многозадачности реального времени в ОС AmigaOS. В данном случае разработка аппаратной и программной части велась параллельно, это привело к тому, что по показателю квантования планировщика многозадачности (1/50 секунды на переключение контекста) AmigaOS долгое время оставалась непревзойдённой на персональных компьютерах.

Многозадачность обеспечивала также фирма Microsoft в операционных системах Windows. При этом Microsoft выбрала две линии разработок — на базе приобретённой ею Windows 0.9, которая после долгой доработки системы, изначально обладавшей кооперативной многозадачностью, аналогичной Mac OS, вылилась в линейку Windows 3.x, и на основе идей, заложенных в VMS, которые привели к созданию операционных систем Windows NT. Использование опыта VMS обеспечило системам существенно более высокую производительность и надёжность. По времени переключения контекста многозадачности (квантование) только эти операционные системы могут быть сравнимы с AmigaOS и UNIX(а также его потомками, такими, как ядро Linux).

Интересно, что многозадачность может быть реализована не только в операционной, но и языковой среде. Например, спецификации языков программирования Modula-2 и Ada требуют поддержки многозадачности вне привязки к какой-либо операционной системе. В результате, популярная в первой половине 1990-х годов реализация языка программирования TopSpeed Модула-2 от JPI/Clarion позволяляла организовывать различные типы многозадачности (кооперативную и вытесняющую — см. ниже) для потоков одной программы в рамках такой принципиально однозадачной операционной системы, как MS-DOS. Это осуществлялось путём включения в модуль программы компактного планировщика задач, содержащего обработчик таймерных прерываний . Языки программирования, обладающие таким свойством, иногда называют языками реального времени.[Источник 1]

Классификация

По типу наименьшего элемента управляемого кода

Процессная многозадачность.

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

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

  • виртуальное адресное пространство;
  • исполнимый код и данные;
  • базовый приоритет;
  • описатели объектов;
  • переменные окружения.

Поточная многозадачность.

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

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

  • Поток определяет последовательность исполнения кода в процессе. 

  • Процесс ничего не исполняет, он просто служит контейнером потоков.

  • Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах.

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

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

Параллельная многозадачность

Идеальным случаем многозадачности является параллельная многозадачность, когда каждая задача исполняется в своём аппаратном микропроцессорном ядре действительно одновременно друг с другом. Истинная многозадачность операционной системы возможна только в распределенных вычислительных системах. Реализация данного типа многозадачности требует больших материальных вложений (требуется отдельное аппаратное средство для каждой задачи), поэтому обычно её применение не является целесообразным. Ниже представлен пример системы , в которой реализована параллельная многозадачность.
Микроконтроллер Propeller от Parallax обеспечивает работу сразу 8 задач. Восемь встроенных процессоров-ядер, могут выполнять как совместные, так и независимые задачи, получая доступ к разделяемым ресурсам посредством центрального переключающего устройства. Разработчик полностью контроллирует, как и когда загружать каждое из ядер; ни компилятор, ни какая-либо операционная система не распределяет задачи между несколькими ядрами. Общий источник тактовой частоты обеспечивает всем процессорам единую временную базу и синхронизацию. Контроллер имеет два возможных языка программирования: легкий для освоения высокоуровневый язык Spin, а так же низкоуровневый Propeller Ассемблер (см. рис. 1).[Источник 2]

Рисунок 1 – Propeller Parallax

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

Типы псевдопараллельной многозадачности

Невытесняющая многозадачность

16-и разрядная Windows уже стала поддерживать и вытесняющую многозадачность (non-preemptive multitasking). Такой тип многозадачности стал возможен благодаря основанной на сообщениях архитектуре Windows.Windows – программа может находиться в памяти и не выполняться до тех пор, пока не получила сообщение. Ранее, эти сообщения часто являлись прямым или косвенным результатом ввода информации пользователем с клавиатуры или мыши. Сейчас, механизм посылки сообщений широко используется и для обмена данными, инициации какого-либо действия приложения и т.п.

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

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

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

Плюсы Минусы
простота реализации затруднена оперативная реакция на внешние события
предсказуемость в поведении, исключение некоторых нежелательных ситуаций, таких как голодание (starvation),гонка (race condition) незащищенность задач друг от друга, снижение надёжности системы — как правило одна неправильно работающая задача блокирует или нарушает работу остальных
минимальные требования к системе и минимизация затрат ресурсов
Совместная или кооперативная многозадачность

Первые операционные системы, реализованные на персональных компьютерах, сильно уступали в концептуальном плане и по своим реальным возможностям системам с разделением времени, давно реализованным в mainframe- компьютерах. В Win 16, например, тоже существует понятие многозадачности. Реализовано оно следующим образом: обработав очередное сообщение, приложение передает управление операционной системе, которая может передать управление другому приложению. Такой вид многозадачности, при котором операционная система передает управление от одного приложения другому не в любой момент времени, а только когда текущее приложение отдает управление системе, получил, как было упомянуто, название кооперативной многозадачности (cooperative multi-tasking).

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

В Windows начиная с Windows 95 реализован принципиально другой вид многозадачности, в котором операционная система действительно контролирует и управляет процессами, потоками и их переключением. Способность операционной системы прервать выполняемый поток практически в любой момент времени и передать управление другому ожидающему потоку определяется термином preemptive multitasking — преимущественная, или вытесняющая, многозадачность. Реализация ее выглядит так: все существующие в данный момент потоки, часть из которых может принадлежать одному и тому же процессу, претендуют на процессорное время и, с точки зрения пользователя должны выполняться одновременно. Для создания этой иллюзии система через определенные промежутки времени забирает управление, анализирует свою очередь сообщений, распределяет сообщения по другим очередям в пространстве процессов и, если считает нужным, переключает потоки (см. рис. 2).

Схема обработки прерывания следующая:

  1. Работа основной программы пользователя.
  2. Возникновение прерывания.
  3. Сохранение параметров работающей программы (регистров процессора).
  4. Переход по адресу процедуры обработки прерывания.
  5. Выполнение процедуры обработки прерывания.
  6. Восстановление параметров работающей программы.
  7. Переход по адресу следующей команды основной программы.

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

Реализация вытесняющей многозадачности в Windows 2000 дает не только возможность плавного переключения задач, но и устойчивость среды к зависаниям, так как ни одно приложение не может получить неограниченные права на процессорное время и другие ресурсы. Так система создает эффект одновременного выполнения нескольких приложений. Если компьютер имеет несколько процессоров, то системы Windows NT/2000 могут действительно совмещать выполнение нескольких приложений. Если процессор один, то совмещение остается иллюзией. Когда заканчивается квант времени, отведенный текущей программе, система ее прерывает, сохраняет контекст и отдает управление другой программе, которая ждет своей очереди. Величина кванта времени (time slice) зависит от ОС и типа процессора, в Windows NT она в среднем равна 20 мс. Следует отметить, что добиться действительно одновременного выполнения потоков можно только на машине с несколькими процессорами и только под управлением Windows NT/2000, ядра которых поддерживают распределение потоков между процессорами и процессорного времени между потоками на каждом процессоре. Windows 95 работает только с одним процессором. Даже если у компьютера несколько процессоров, под управлением Windows 95 задействован лишь один из них, а остальные простаивают.[Источник 3]

Рисунок 2 – Переключение потоков

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

Диспетчеризация

Эффективность многозадачной системы во многом зависит от способа диспетчеризации задач на исполнение.

Состояние задачи

Для понимания диспетчеризации важным является понятие состояния задачи. Основные состояния задач такие:

  • выполняется;
  • готова к исполнению;
  • заблокирована.

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

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

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

Стратегии диспетчеризации

Известно несколько основных стратегий диспетчеризации:

  • круговая (round-robin).Управление между задачами производится в в каком-либо фиксированном порядке через определённые промежутки времени;
  • случайная (random).Через каждый определённый промежуток времени управление передаётся на произвольную задачу;
  • приоритетная (priority-driven).Каждая задача имеет уровень приоритета и управление получает незаблокированная задача имеющая наибольший уровень;
  • управляемая дедлайнами (deadline-driven). Передача управления производится в порядке, обеспечивающем выполнение задач в определённый срок.[Источник 1]

Программная реализация многозадачности

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

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

Для 16-битных приложений используется функция WinExec:

UINT WinExec(

LPCSTR lpCmdLine, // command line

UINT uCmdShow// window style
);

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

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

В среде Windows 32 следует использовать другой способ порождения процессов:

BOOL CreateProcess(

LPCTSTR lpApplicationName,	// pointer to name of executable module

LPTSTR lpCommandLine,	// pointer to command line string

LPSECURITY_ATTRIBUTES lpProcessAttributes,	// pointer to process security attributes

LPSECURITY_ATTRIBUTES lpThreadAttributes,	// pointer to thread security attributes

BOOL bInheritHandles,	// handle inheritance flag

DWORD dwCreationFlags,	// creation flags

LPVOID lpEnvironment,	// pointer to new environment block

LPCTSTR lpCurrentDirectory,	// pointer to current directory name

LPSTARTUPINFO lpStartupInfo,	// pointer to STARTUPINFO

LPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_INFORMATION

);

Первый параметр является указателем на имя запускаемого файла. Имя может содержать полный путь к файлу (диск:каталог…файл). Если имя не содержит пути, то операционная система ищет файл в текущем каталоге, затем в системных каталогах и в каталогах, указанных в разделе PATH при загрузке системы.

Второй параметр указывает на командную строку.

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

bInheritHandles и dwCreationFlags содержит дополнительные флаги управления созданием и приоритетом процесса.

lpEnvironment содержит указатель на буфер памяти, в котором будет создаваться служебная информация по процессу. Если равен NULL, то операционная система сама отводит место в памяти под эту информацию.

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

lpStartupInfo определяет структуру STARTUPINFO , которая описывает окно, создаваемое для запускаемого процесса (в ней содержится информация, похожая на ту, которая передается в процедуру CreateWindow).

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

Многопоточность в программе реализовать можно несколькими путями.

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

Использование системного таймера для организации посылки синхронных сообщений выбранному окну (порядок организации описан в лекции «Использование Таймера»). С помощью данного способа реализуется невытесняющая многозадачность. Достоинство – изменяемая периодичность посылки сообщений. Недостаток – природа синхронных сообщений не гарантирует четкое выполнение периода прихода сообщений от таймера.

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

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread1,&params,0,&iThread);

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

Второй параметр определяет начальный адрес потока (фактически — имя процедуры потока), например:

DWORD WINAPI Thread1(PVOID pvoid)
{
// Текст потока
}

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

Четвертый параметр определяет дополнительные флаги создания потока. Если этот параметр равен нулю, то поток создастся немедленно.

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

Использование функции Sleep

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

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

Критические разделы

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

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

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

Данный участок потока называется критическим разделом. Существует четыре функции работы с критическим разделом. Чтобы их использовать необходимо определеить объект типа критический раздел:

CRITICAL_SECTION cs;

Объект типа критический раздел сначала должен быть инициализирован одним из потоков программы с помощью функции:

InitializeCriticalSection(&cs);

Эта функция создает критический раздел с именем cs.После инициализации объекта «критический раздел» поток входит в критический раздел, вызывая функцию:

EnterCriticalSection(&cs);

В этот момент поток становиться владельцем объекта. Два различных потока не могут быть владельцами одного объекта одновременно. Следовательно, если один поток вошел в критический раздел, то следующий поток, вызывая функцию EnterCriticalSection(&cs); с тем же самым объектом, будет задержан внутри функции. Возврат из функции произойдет только тогда, когда первый поток покинет критический раздел, вызвав функцию:

LeaveCriticalSection(&cs);

В этот момент второй поток, задержанный в функции EnterCriticalSection(&cs), станет владельцем критического раздела, и его выполнение будет возобновлено.

Когда критический раздел больше не нужен вашей программе, его можно удалить с помощью функции:

DeleteCriticalSection(&cs);

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

Программа может создавать несколько критических разделов. Существенное ограничение при использовании критических разделов состоит в том, что таким образом можно синхронизировать только потоки одного процесса и нельзя осуществить синхронизацию процессов (действительно, ведь переменная cs объявлена в процессе и не видна из других процессов).[Источник 4]

Использование событий

Альтернативным вариантом синхронизации является использование событий. Объект событие может быть либо свободным (signaled) или установленным (set), либо занятым (non-signaled) или сброшенным (reset). Вы можете создать объект «событие» с помощью функции:

hEvent = CreateEvent(&sa, fManual, fInitial, pszName);

Первый параметр — указатель на структуру SECURITY_ATTRIBUTES, устанавливающую параметры использования события потоками и процессами.

Параметр fInitial устанавливается в TRUE, если вы хотите, чтобы объект Событие был изначально свободным, или в FALSE, чтобы он был занятым.

Параметр psz Name определяет имя события. По этому имени разные процессы могут использовать одно событие.

Для того, чтобы сделать свободным существующий объект Событие, надо вызвать функцию:

SetEvent(hEvent);

Чтобы сделать объект Событие занятым, вызывается функция:

ResetEvent(hEvent);

Для синхронизации используется функция:

WaitForSingleObject(hEvent, dwTimeOut);

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

Если параметр fManual имеет значение FALSE при вызове функции CreateEvent, то объект Событие автоматически становится занятым, когда осуществляется возврат из функции WaitForSingleObject. Эта особенность позволяет избежать использования функции ResetEvent.[Источник 4]

Проблемные ситуации в многозадачных системах

Рисунок 3 – Взаимосвязь потоков и процессов

Голодание (starvation)

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

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

Голодание создаёт узкое место в системе и не дает выжать из неё максимальную производительность, ограничиваемую только аппаратно обусловленными узкими местами.

Любое голодание вне 100 % загрузки процессора может быть устранено повышением приоритета голодающей нити, возможно — временным.

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

Гонка (race condition)

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

Устраняется добавлением необходимых блокировок и примитивов синхронизации. Обычно является легко устраняемым дефектом (забытая блокировка).

Инверсия приоритета

Поток L имеет низкий приоритет, поток M — средний, поток H — высокий. Поток L захватывает mutex, и, выполняясь с удержанием mutex’а, прерывается потоком M, который пробудился по какой-то причине, и имеет более высокий приоритет. Поток H пытается захватить mutex.

В полученной ситуации поток H ожидает завершения текущей работы потоком M, ибо, пока поток M исполняется, низкоприоритетный поток L не получает управления и не может освободить mutex.

Устраняется повышением приоритета всех нитей, захватывающих данный mutex, до одного и того же высокого значения на период удержания mutexa. Некоторые реализации mutex’ов делают это автоматически.[Источник 4]

Процессы в Windows и потоковая многозадачность

Рисунок 4 – Пример работы планировщика

Windows — это многозадачная операционная система, то есть она может одновременно выполнять две и более программ. Конечно, программы используют единственный процессор и, строго говоря, выполняются не одновремен­но. Однако высокое быстродействие компьютера создает такую иллюзию. Windows поддерживает два типа многозадачности: процессную и потоковую (см. рис. 3).

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

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

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

Многозадачность в Linux

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

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

К каждому процессу в системе привязаны идентификатор процесса PID (Process IDentifier) и идентификатор родительского процесса PPID (Parent Process IDentifier). Для каждого процесса PID является уникальным (в конкретный момент времени), а PPID равен идентификатору процесса-родителя.

Использование getpid() и getppid()

Процесс может узнать свой идентификатор (PID), а также родительский идентификатор (PPID) при помощи системных вызовов getpid() и getppid().

Системные вызовы getpid() и getppid() имеют следующие прототипы:pid_t getpid (void); pid_t getppid (void);

Для использования getpid() и getppid() в программу должны быть включены директивой #include заголовочные файлы unistd.h и sys/types.h (для типа pid_t). Вызов getpid() возвращает идентификатор текущего процесса (PID), а getppid() возвращает идентификатор родителя (PPID). pid_t — это целый тип, размерность которого зависит от конкретной системы. Значениями этого типа можно оперировать как обычными целыми числами типа int.

Рассмотрим теперь простую программу, которая выводит на экран PID и PPID, а затем «замирает» до тех пор, пока пользователь не нажмет <Enter>.

/* getpid.c */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main (void)
{
        pid_t pid, ppid;

        pid = getpid ();
        ppid = getppid ();

        printf ("PID: %dn", pid);
        printf ("PPID: %dn", ppid);

        fprintf (stderr, "Press <Enter> to exit...");
        getchar ();
        return 0;
}

Проверим теперь, как работает эта программа. Для этого откомпилируем и запустим ее:

$ gcc -o getpid getpid.c
$ ./getpid
PID: 27784
PPID: 6814
Press <Enter> to exit...

Теперь, не нажимая <Enter>, откроем другое терминальное окно и проверим, правильность работы системных вызовов getpid() и getppid():[Источник 4]

$ ps -ef | grep getpid
nn       27784  6814  0 01:05 pts/0    00:00:00 ./getpid
nn       28249 28212  0 01:07 pts/1    00:00:00 grep getpid

Источники

  1. 1,0 1,1 1,2 1,3 1,4 Полный справочник по Java // Герберт Шилдт [2019]. Дата изменения: 01.01.2009. URL: https://www.books.ru/books/polnyi-spravochnik-po-java-7-e-izdanie-3643725/ (дата обращения: 10.04.2019).
  2. ИМС Propeller от PARALLAX // Инженерная группа 6-LAB [2019]. Дата изменения: 07.03.2017. URL: https://web.archive.org/web/20170307195743/http://6-lab.com/ru/techarticles/propellerarticle.html (дата обращения: 10.04.2019).
  3. Многозадачные операционные системы // Programming land [2019]. Дата изменения: 23.12.2016. URL: http://programming-lang.com/html/visual_studio.net/glava12/index5.htm (дата обращения: 10.04.2019).
  4. 4,0 4,1 4,2 4,3 4,4 МНОГОЗАДАЧНОСТЬ // openNET [1996–2019]. Дата изменения: 01.01.2007. URL: https://www.opennet.ru/docs/RUS/zlp/006.html (дата обращения: 10.04.2019).
  5. Процессы в Windows и потоковая многозадачность // Scritube [2019]. Дата изменения: 07.03.2017. URL: http://www.scritub.com/limba/rusa/Windows11518232111.php (дата обращения: 10.04.2019).
  • v
  • t
  • e

Операционные системы

Общая информация
  • Сравнение
  • Разработка криминалистического ПО
  • История
  • Список
  • Хронология
  • Доля использования
Ядро

Архитектура

  • Экзо
  • Гибридное
  • Микро
  • Монолитное
  • Нано

Компоненты

  • Драйвер
  • LKM
  • Микроядро
  • Пространство пользователя
Управление процессами

Аспекты

  • Переключение контекста
  • Прерывание
  • IPC
  • Процесс
  • Блок управления процессом
  • RTOS
  • Поток
  • Разделение времени

Планировщик
задач

  • Многозадачность
  • Упреждающее планирование с фиксированным приоритетом
  • Многоуровневые очереди с обратной связью
  • Вытесняющая многозадачность
  • Round-robin
  • SJN (Shortest job next)
Управление памятью
  • Ошибка на шине
  • Общая ошибка защиты
  • Защита памяти
  • Подкачка страниц
  • Кольца защиты
  • Ошибка сегментации
  • Виртуальная память
  • Страничная память
  • Сегментная адресация памяти
Память для хранения
Файловые системы
  • Загрузчик
  • Дефрагментация
  • Файл устройства
  • Атрибут файла
  • Inode
  • Журнал
  • Раздел диска
  • Виртуальная файловая система
  • VTL
Список
  • AmigaOS
  • Android
  • BeOS
  • BSD
  • Chrome OS
  • Cosmos
  • CP/M
  • Darwin
  • DOS
  • Genode
  • GNU
  • Haiku
  • illumos
  • IncludeOS
  • iOS
    • watchOS
    • tvOS
    • audioOS
  • ITS
  • Linux
  • Mac OS
    • Classic Mac OS
    • macOS
  • MINIX
  • MorphOS
  • MUSIC/SP
  • Nemesis
  • NeXTSTEP
  • NOS
  • OpenVMS
  • ORVYL
  • OS/2
  • OS-9
  • OSv
  • Pick
  • QNX
  • ReactOS
  • RISC OS
  • RSTS/E
  • RSX-11
  • RT-11
  • Solaris
  • TOPS-10/TOPS-20
  • z/TPF
  • TRIPOS
  • UNIX
  • Visi On
  • VM/CMS
  • VS/9
  • webOS
  • Windows
  • Xinu
  • z/OS
Прочее
  • API
  • Computer network
  • HAL
  • Live CD
  • Live USB
  • OS shell
    • CLI
    • GUI
    • NUI
    • TUI
    • VUI
    • ZUI
  • PXE

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

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

Windows 10 — это многозадачная операционная система?

Изучите три различных способа многозадачности и использования нескольких рабочих столов в Windows 10. Нажмите кнопку «Просмотр задач» или нажмите Alt-Tab на клавиатуре, чтобы просматривать приложения или переключаться между ними. Чтобы использовать два или более приложений одновременно, возьмитесь за верхнюю часть окна приложения и перетащите его в сторону.

Что означает многозадачность в ОС?

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

Также известна как многозадачная операционная система?

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

Что такое класс многозадачности 11?

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

Какие два типа многозадачности?

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

Что такое многозадачность приведите пример?

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

Что такое многозадачность и ее виды?

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

Как ОС поддерживает многозадачность?

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

Понравилась статья? Поделить с друзьями:
  • Повысить редакцию windows server 2008 r2
  • Повысить производительность компьютера windows 10 программа
  • Повысить громкость микрофона windows 10 программа
  • Повысить версию windows 10 до про
  • Повысить версию windows 10 до pro без переустановки