ЛЕКЦИЯ 4 – множество заблокированных процессов, каждый из которых владеет некоторым ресурсом и ожидает ресурса, которым владеет какой-либо другой процесс из этого множества. Простой пример тупика легко смоделировать с помощью семафоров. — ОДНО ИЗ СРЕДСТВ РАЗДЕЛЕНИЯ ДОСТУПА К КРИТИЧЕСКИМ РЕСУРСАМ ПАРАЛЛЕЛЬНО РАБОТАЮЩИХ ПРОЦЕССОВ. СЕМАФОРЫ БЫЛИ ВВЕДЕНЫ ЭДСГЕРОМ ДЕЙКСТРА ЕЩЕ В 1965 ГОДУ. АЛГОРИТМ ИСПОЛЬЗОВАНИЯ СЕМАФОРОВ ВЫГЛЯДИТ ТАК: Пусть в системе есть два внешних устройства a и b, к которым обращаются два процесса p1 и p2. С каждым из внешних устройств с целью синхронизации связан семафор, которые будем обозначать также a и b. Семафоры изначально открыты. Пусть каждому из процессов необходимы оба устройства, но они обращаются к ним в противоположном порядке: В данном случае будет иметь место тупик: процесс p1, закрыв семафор a и заблокировав первое устройство, никогда не дождётся, когда откроется семафор b, связанный со вторым устройством, так как его уже успел закрыть процесс p2. Аналогично, процесс p2 никогда не дождется, когда откроется семафор A. ОПЕРАЦИЯ WAIT(S) НАД СЕМАФОРОМ S СОСТОИТ В СЛЕДУЮЩЕМ: А ОПЕРАЦИЯ SIGNAL(S) ЗАКЛЮЧАЕТСЯ В ТОМ, ЧТО: Работа семафоров Семафоры со счетчиками используются, если некоторый ресурс выделяется из множества идентичных ресурсов. При инициализации такого семафора в его счетчике указывается число элементов множества ресурсов. Каждая операция уменьшает значения счетчика семафора s на 1, показывая, что некоторому процессу выделен один ресурс из множества. Каждая операция увеличивает значение счетчика на 1, показывая, что процесс возвратил ресурс во множество. Если операция выполняется, когда в счетчике содержится нуль (больше нет ресурсов), то соответствующий процесс ожидает, пока во множество не будет возвращен освободившийся ресурс, то есть пока не будет выполнена операция . Пример семафоров Есть некоторое число читателей, которые приходят в библиотеку три раза в день и там читают книги. И пусть будет ограничение, что единовременно в библиотеке не может находиться больше трех читателей. Данную задачу очень легко решить с помощью семафоров using system; using system.threading; namespace semaphoreapp { class program { static void main(string[] args) { for (int i = 1; i < 6; i++) { reader reader = new reader(i); } console.readline(); } } class reader Тупиковые ситуации 1. ТРАНСПОРТНАЯ ПРОБКА 2. УДЕРЖАНИЕ РЕСУРСА ЗАПРАШИВАЕМОГО ДРУГИМ ПРОЦЕССОМ Тупиковые ситуации 3. ТУПИК ПРИ СПУЛЛИНГЕ (Ввод-вывод с буферизацией). Буфер может переполниться и очищаться до начала ввода/вывода. 4. БЕСКОНЕЧНОЕ ОТКЛАДЫВАНИЕ. В системе, где процессам приходится ждать, пока она принимает решения по распределению ресурсов и планированию, возможно возникновение ситуации, при которой предоставление процессора некоторому процессу будет откладываться на неопределенно долгий срок, в то время как система будет уделять внимание другим процессам. Бесконечное откладывание процесса может происходить из-за «дискриминационной» политики планировщика ресурсов системы. Когда ресурсы распределяются по приоритетному принципу, может случиться, что данный процесс будет бесконечно долго ожидать выделения нужного ему ресурса, поскольку будут постоянно приходить процессы с более высокими приоритетами. Ожидание — непременный факт нашей жизни и безусловно важный аспект внутренней работы вычислительных машин. При разработке операционных систем необходимо предусматривать справедливое, а также эффективное управление процессами, находящимися в состоянии ожидания. Четыре необходимых условия возникновения тупика Процессы требуют предоставления им права монопольного управления ресурсами, которые им выделяются (условие взаимоисключения) . Процессы удерживают за собой ресурсы, уже выделенные им, ожидая в то же время выделения дополнительных ресурсов (условие ожидания ресурсов). Ресурсы нельзя отобрать у процессов, удерживающих их, пока эти ресурсы не будут использованы для завершения работы (условие неперераспределяемости). Существует кольцевая цепь процессов, в которой каждый процесс удерживает за собой один или более ресурсов, требующихся следующему процессу цепи (условие кругового ожидания). МОДЕЛЬ СИСТЕМЫ Пусть в системе имеется m видов ресурсов (например, процессор, память, устройства ввода-вывода). Будем обозначать типы ресурсов в системе R1, R2, … Rm. Пусть каждый тип ресурса ri имеет wi экземпляров. Каждый процесс может использовать ресурс одним из следующих способов: Тупик может возникнуть, если одновременно выполняются следующие четыре условия: • ВЗАИМНОЕ ИСКЛЮЧЕНИЕ: ТОЛЬКО ОДИН ПРОЦЕСС В КАЖДЫЙ МОМЕНТ ВРЕМЕНИ МОЖЕТ ПОЛУЧИТЬ ДОСТУП К РЕСУРСУ; • УДЕРЖАНИЕ И ОЖИДАНИЕ: ПРОЦЕСС, УДЕРЖИВАЮЩИЙ ОДИН РЕСУРС, ОЖИДАЕТ ПРИОБРЕТЕНИЯ ДРУГИХ РЕСУРСОВ, КОТОРЫМИ ОБЛАДАЮТ ДРУГИЕ ПРОЦЕССЫ; • ОТСУТСТВИЕ ПРЕРЫВАНИЙ: ПРОЦЕСС МОЖЕТ ОСВОБОДИТЬ РЕСУРС ТОЛЬКО ДОБРОВОЛЬНО, КОГДА ЗАВЕРШИТ СВОЮ РАБОТУ; • ЦИКЛИЧЕСКОЕ ОЖИДАНИЕ: СУЩЕСТВУЕТ МНОЖЕСТВО {P0, P1, … PN}, ТАКОЕ, ЧТО P0 ОЖИДАЕТ РЕСУРСА, КОТОРЫМ ОБЛАДАЕТ P1; P1 ОЖИДАЕТ РЕСУРСА, КОТОРЫМ ОБЛАДАЕТ P2 … PN И Т.Д. ГРАФ РАСПРЕДЕЛЕНИЯ РЕСУРСОВ: Введем в рассмотрение граф распределения ресурсов, состоящий из множества вершин ^ V и множества дуг E. V подразделяется на два типа вершин: вершина-процесс и вершинаресурс. Иначе говоря, V подразделяется на вершины типа P = {P1, P2, … ,Pn} множество всех процессов в системе, и вершины типа R = {R1, R2, … ,Rm} множество всех ресурсов системы. Введем два типа дуг: Смысл различных направленностей дуг в следующем: Если процесс претендует на какой-либо ресурс, то дуга проводится из вершины-процесса в вершину-ресурс. Когда же конкретная единица ресурса уже выделена какому-либо конкретному процессу, то дуга, в знак этой принадлежности, и проводится из вершины-ресурса в вершину процесс, наоборот. ВЕРШИНА ПРОЦЕССА (Например tasking.Exe – обработчик планировщика заданий) ВЕРШИНА РЕСУРСА С ЧЕТЫРЬМЯ ЭКЗЕМПЛЯРАМИ (Например 4 ядра) Rj (W1-W4) Пример графа распределения ресурсов Данный граф изображает систему с тремя процессами и четырьмя видами ресурсов: ресурсы видов 1 и 3 имеют по одному экземпляру, ресурс вида 2 – два экземпляра, ресурс вида 4 – три экземпляра. Процесс 1 претендует на ресурс 1, который занят процессом 2. Процесс 2 претендует на ресурс 3, который занят процессом 3. Две единицы ресурса 2 отданы процессам 1 и 2. Ресурс 4 не распределялся (все три единицы свободны). Цикл в таком графе может означать наличие тупика. Если провести дугу из P3 в R2, то образуется тупик. • ЕСЛИ ГРАФ РАСПРЕДЕЛЕНИЯ РЕСУРСОВ НЕ СОДЕРЖИТ ЦИКЛОВ, ТО В СИСТЕМЕ ТУПИКОВ НЕТ; • ЕСЛИ ГРАФ РАСПРЕДЕЛЕНИЯ РЕСУРСОВ СОДЕРЖИТ ЦИКЛ, ТО ВОЗМОЖНО ДВА СЛУЧАЯ: ЕСЛИ РЕСУРСОВ КАЖДОГО ВИДА ИМЕЕТСЯ ТОЛЬКО ПО ОДНОМУ ЭКЗЕМПЛЯРУ, ТО ИМЕЕТ МЕСТО ТУПИК; ЕСЛИ РЕСУРСОВ ПО НЕСКОЛЬКО ЭКЗЕМПЛЯРОВ, ТО ТУПИК ВОЗМОЖЕН. МЕТОДЫ ОБРАБОТКИ ТУПИКОВ Теоретически возможны следующие методы обработки тупиков: • Убедиться в том, что система никогда не войдет в состояние тупика; • Допустить, чтобы система могла входить в состояние тупика, но предусмотреть возможность восстановления после тупика. БЕЗОПАСНОЕ СОСТОЯНИЕ СИСТЕМЫ Безопасным состоянием назовем такое состояние, перевод системы в которое не приведет к появлению тупиков. Общий принцип избегания тупиков состоит в следующем. Когда процесс запрашивает доступный ресурс, система должна определить, приведет ли немедленное выделение данного ресурса к безопасному состоянию системы. Система находится в безопасном состоянии, если существует безопасная последовательность, состоящая из всех процессов в системе. Безопасной последовательностью процессов называется последовательность процессов <P1, … Pn>, такая, что для каждого процесса Pi ресурсы, которые он может еще запросить, могут быть выделены из текущих доступных ресурсов и ресурсов, удерживаемых процессами Pj , где j < i. ПРИНЦИПЫ АЛГОРИТМА БАНКИРА: Алгоритм банкира для безопасного распределения ресурсов операционной системой (с избеганием тупиков) был предложен Э. Дейкстрой и впервые реализован в конце 1960-х гг. Происхождение названия связано с тем, что поведение алгоритма напоминает осторожную стратегию банкира при проведении банковских операций. Принципы алгоритма банкира следующие. Каждый процесс должен априорно обозначить свои потребности в ресурсах по максимуму. Когда процесс запрашивает ресурс, ему, возможно придется подождать (выделение ресурсов по запросу не всегда может произойти немедленно). Когда процесс получает требуемые ресурсы, он должен их вернуть системе за ограниченный период времени. СТРУКТУРЫ ДАННЫХ ДЛЯ АЛГОРИТМА БАНКИРА: Пусть в системе имеется n процессов и m типов ресурсов. Вектор available длины m содержит информацию о доступных ресурсах. Если avaliable[j] = k, то в системе в данный момент доступно k единиц ресурса j. Матрица max (n * m) отображает максимальные потребности процессов в ресурсах. Если max [i, j] = k, то процесс i может запросить, самое большее, k единиц ресурса j. Матрица allocation (n * m) отображает фактическое выделение системой ресурсов. Если allocation [i, j] = k, то процессу i в данный момент выделено системой k единиц ресурса j. Матрица need (n * m) отображает оставшиеся потребности процессов в ресурсах. Если need [i, j] = k, то процессу i могут потребоваться еще k единиц ресурса j для завершения работы. СТРУКТУРЫ ДАННЫХ ДЛЯ АЛГОРИТМА БАНКИРА: Имеет место следующее соотношение между элементами матриц: need [i, j] = max [i, j] – allocation [i, j]. Введем целочисленный вектор work (длины m) и булевский вектор finish (длины n). Вектор work отображает пробные выделения ресурсов. Вектор finish представляет информацию о завершаемости процессов при данном состоянии системы. Алгоритм безопасности : ШАГ 1. ИНИЦИАЛИЗАЦИЯ. WORK = AVAILABLE FINISH [I] = FALSE ДЛЯ I = 1, …, N. ЗДЕСЬ И В ДАЛЬНЕЙШЕМ ВСЕ ПРИСВАИВАНИЯ И СРАВНЕНИЯ, В КОТОРЫХ УЧАСТВУЮТ ВЕКТОРЫ ИЛИ МАТРИЦЫ, ВЫПОЛНЯЮТСЯ ПОЭЛЕМЕНТНО. ШАГ 2. НАХОДИМ I, ТАКОЕ, ЧТО: FINISH [I] = FALSE NEED [I] <= WORK ЕСЛИ ТАКОГО I НЕТ, ПЕРЕХОДИМ К ШАГУ 4. ШАГ 3. WORK = WORK ALLOCATION [I] FINISH [I] = TRUE ПЕРЕХОД К ШАГУ 2. ШАГ 4. ЕСЛИ FINISH[I] = TRUE ДЛЯ ВСЕХ I = 1, …, N, ТО СИСТЕМА В БЕЗОПАСНОМ СОСТОЯНИИ. Алгоритм запроса ресурсов для процесса Pi – основная часть алгоритма банкира : Для основного алгоритма введем вектор requesti (длины m) – вектор запросов для процесса pi . если requesti [j] = k, то процесс pi запрашивает k экземпляров ресурса rj. Шаг 1. Если requesti <= need[i], перейти к шагу 2. Иначе – сгенерировать исключительную ситуацию (процесс превысил свои максимальные потребности). Шаг 2. Если requesti <= available, перейти к шагу 3. Иначе процесс должен ждать, так как ресурс недоступен. Шаг 3. Спланировать выделение ресурса процессу pi , модифицируя состояние системы следующим образом: available = available - requesti allocation = allocation requesti need [i] = need [i] - requesti вызвать алгоритм проверки безопасности полученного состояния. Если состояние безопасно, выделить ресурс процессу pi . выход. Если состояние небезопасно, восстановить предыдущее состояние; процесс должен ждать.