Процессы и потоки в Windows. Операционные системы

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

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

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

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

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

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

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


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

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


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

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

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

7 ответов

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

Кроме того, даже если вы можете запустить 5000+ потоков, в зависимости от вашего оборудования, которые могут работать намного медленнее, чем 10-нить-эквивалентная программа. Я думаю, вы должны взглянуть на объединение потоков .

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

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

Честно говоря, я бы сказал, что я много занимаюсь многопоточным в.NET/Windows, потому что у человека обычно есть больше "повреждений", чем пользы, когда у вас нет реального понимания..NET имеет концепцию пула потоков, и вам нужно знать, как это работает в дополнение к Windows.

В.NET 3.5/4.0 вы должны смотреть на Задачи (Task Parallel Library), поскольку библиотека намного лучше определяет, как много нитей (если вообще) икру. С TPL threadpool получает капитальный ремонт, и он намного умнее в вопросе о размножении потоков и краже задач и т.д. Но вы обычно работаете с задачами, а не с потоками.

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

Каждый поток потребляет больше памяти (стек ядра, блок среды потока, thread-local, stack....). AFAIK в Windows нет явного ограничения, поэтому ограничение будет памятью (вероятно, стек для каждого потока).

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

Cat /proc/sys/kernel/threads-max

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

Да, вы можете запускать больше задач, но они будут ждать ресурсов (или потоков в пуле потоков), и ваш ящик, независимо от размера, не может полностью распределить все основные ресурсы процессора в 100% случаев поток из-за фона/других процессов. Таким образом, чем больше задач вы создаете, тем больше потоков вы создаете, поскольку они превосходят фактические возможные параллельные потоки (1 на ядро), тем больше будет выполняться управление ресурсами, очередность и свопинг.

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

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

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

Чтобы определить это программно, мы используем

var CoreCount = System.Environment.ProcessorCount / 2;

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

Мне удалось запустить 4 потока одновременно на моем текущем старом процессоре (2005). Использование EVGA CPU burner до того, как прозвучал мой зуммер процессора. (Запрограммировано в меню BIOS). Значение я превысило 90 * c. Имейте в виду, что мы говорим о потоках данных, работающих одновременно. хорошим примером может быть одновременное открытие нескольких программ. Но в целом это зависит от того, насколько хорош ваш процессор с многозадачностью. (другими словами, можно обрабатывать многие активные потоки). Безопасным способом тестирования является загрузка "ocscanner (By EVGA)" и "CPU Thermometer" с использованием центрального процессора в OC Scanner. Во время тестирования убедитесь, что ваша температура не превышает 90 * c (или любую температуру, в которой вы чувствуете себя в безопасности) и посмотрите на текущее количество потоков, которые вы запускаете, бросили ваш процессор. начните с 2 потоков, подождите 3-5 минут, наблюдая температуру процессора, добавьте еще один поток, повторите. (НЕ ПРИНИМАЙТЕ СВОЮ УДАЧУ!!!) (НЕ ПОПЫТАЙТЕ, ЕСЛИ ТЕРМОМЕТР ЦП НЕ МОЖЕТ СДЕЛАТЬ ВАШУ ТЕМПЕРАТУРУ!!!)

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

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

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

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

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

4.1 Процессы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Регистры

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

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

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

Приоритет

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Состояние

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

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

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

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

  • Семафоры

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

В общем случае дескриптор содержит следующую информацию:

  1. Идентификатор процесса.
  2. Тип (или класс) процесса, который определяет для супервизора некоторые правила предоставления ресурсов.
  3. Приоритет процесса.
  4. Переменную состояния, которая определяет, в каком состоянии находится процесс (готов к работе, в состоянии выполнения, ожидание устройства ввода-вывода и т.д.)
  5. Защищенную область памяти (или адрес такой зоны), в которой хранятся текущие значения регистров процессора, если процесс прерывается, не закончив работы. Эта информация называется контекстом задачи .
  6. Информацию о ресурсах, которыми процесс владеет и/или имеет право пользоваться (указатели на открытые файлы, информация о незавершенных операциях ввода/вывода и т.п.).
  7. Место (или его адрес) для организации общения с другими процессами.
  8. Параметры времени запуска (момент времени, когда процесс должен активизироваться, и периодичность этой процедуры).
  9. В случае отсутствия системы управления файлами – адрес задачи на диске в ее исходном состоянии и адрес на диске, куда она выгружается из оперативной памяти, если ее вытесняет другая.

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

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

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

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

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

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

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

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

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

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

Можно выделить следующие отличия потоков от процессов :

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

Главное, что обеспечивает многопоточность , — это возможность параллельно выполнять несколько видов операций в одной прикладной программе. За счет чего реализуется эффективное использование ресурсов ЦП, а суммарное время выполнения задач становится меньше.

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

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

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

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

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

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

На вкладке Быстродействие, отображаются сведения о счетчике дескрипторов и потоках, параметры памяти:

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

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

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

Пример . Задача ведения базы данных клиентов некоторого предприятия.

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

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

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

  1. Считать из файла БД в буфер запись и клиенте с заданным идентификатором.
  2. Ввести новое значение в поле Заказ (для потока А) или оплата (для потока В).
  3. Вернуть модифицированную запись в файл БД.

Обозначим шаги 1-3 для потока А как А1-А3, а для потока В как В1-В3. Предположим, что в некоторый момент поток А обновляет поле Заказ записи о клиенте N. Для этого он считывает эту запись в свой буфер (шаг А1), модифицирует значение поля Заказ (шаг А2), но внести запись в базу данных не успевает, так как его выполнение прерывается, например, вследствие истечение кванта времени.

Предположим, что потоку В также потребовалось внести сведения об оплате относительно того же клиента N. Когда подходит очередь потока В, он успевает считать запись в свой буфер (шаг В1) и выполнить обновление поля Оплата (шаг В2), а затем прерывается. Заметим, что в буфере у потока В находится запись о клиенте N, в которой поле Заказ имеет прежнее, не измененное значение.

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

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

Другим способом является использование блокирующих переменных. С каждым разделяемым ресурсом связывается двоичная переменная, которая принимает значение 1, если ресурс свободен (то есть ни один процесс не находится в данный момент в критической секции, связанной с данным процессом), и значение 0, если ресурс занят. На рисунке ниже показан фрагмент алгоритма процесса, использующего для реализации взаимного исключения доступа к разделяемому ресурсу D блокирующую переменную F(D). Перед входом в критическую секцию процесс проверяет, свободен ли ресурс D. Если он занят, то проверка циклически повторяется, если свободен, то значение переменной F(D) устанавливается в 0, и процесс входит в критическую секцию. После того, как процесс выполнит все действия с разделяемым ресурсом D, значение переменной F(D) снова устанавливается равным 1.

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

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

Если ресурс занят, то процесс не выполняет циклический опрос, а вызывает системную функцию WAIT(D), здесь D обозначает событие, заключающееся в освобождении ресурса D. Функция WAIT(D) переводит активный процесс в состояние ОЖИДАНИЕ и делает отметку в его дескрипторе о том, что процесс ожидает события D. Процесс, который в это время использует ресурс D, после выхода из критической секции выполняет системную функцию POST(D), в результате чего операционная система просматривает очередь ожидающих процессов и переводит процесс, ожидающий события D, в состояние ГОТОВНОСТЬ.

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

V(S): переменная S увеличивается на 1 одним неделимым действием; выборка, инкремент и запоминание не могут быть прерваны, и к S нет доступа другим процессам во время выполнения этой операции.

P(S): уменьшение S на 1, если это возможно. Если S=0, то невозможно уменьшить S и остаться в области целых неотрицательных значений, в этом случае процесс, вызывающий P-операцию, ждет, пока это уменьшение станет возможным. Успешная проверка и уменьшение также является неделимой операцией.

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

Взаимоблокировка процессов

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

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

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

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

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

  1. предотвращение тупиков.
  2. распознавание тупиков.
  3. восстановление системы после тупиков.

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

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

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