КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Общие ресурсы
Трудно переоценить важность правильной организации взаимодействия различных задач при доступе к общим ресурсам. Хорошей аналогией может служить обед в многодетной крестьянской семье прошлого века. Едокам (задачам) не разрешалось одновременно лезть ложками в общую миску (ресурс). Нарушители порядка могли получить от отца семейства (супервизора) ложкой по лбу. Ресурс - это общий термин, описывающий физическое устройство или область памяти, которые могут одновременно использоваться только одной задачей. Процессорное время тоже представляет собой своеобразный конкурентно используемый ресурс вычислительной системы. Примером физических устройств могут служить клавиатура, дисплей, дисковый накопитель, принтер и т.п. Представим, например, что несколько задач пытаются одновременно выводить данные на принтер. На распечатке в результате ничего, кроме странной мешанины символов, мы не увидим. В качестве другого примера рассмотрим ситуацию, когда в бортовом компьютере мирно летящего самолета МИГ-29 среди прочих работают две задачи. Одна из них, взаимодействуя с радиолокационной системой, выдает удаление и направление до цели, а другая задача использует эти данные для пуска ракет класса «воздух-воздух». Не исключено, что первая задача, записав в глобальную структуру данных удаление до цели, будет прервана второй задачей, не успев записать туда направление до цели. В результате вторая задача считает из этой структуры ошибочные данные, что может привести к неудачному пуску со всеми вытекающими отсюда неприятными последствиями. Прервись первая задача чуть позже, и все было бы нормально. Упомянутые здесь проблемы обусловлены времязависимыми ошибками (time dependent error), или «гонками» и характерны для многозадачных ОС, применяющих алгоритмы планирования с вытеснением (кстати, системы с разделением времени также относятся к категории «вытесняющих»). Приведенный пример показывает, что ошибки, обусловленные «гонками», а) характерны для работы с любыми ресурсами, доступ к которым имеют несколько задач, и б) происходят только в результате совпадения определенных условий, а потому с трудом обнаруживаются на этапе отладки. Вот возможные пути решения проблемы. 1. Не использовать алгоритмы планирования задач с вытеснением. Это решение, правда, не всегда приемлемо. 2. Использовать специальный сервер ресурса, то есть задачу, ответственную за упорядочивание доступа к ресурсу. В этом случае запрос на изменение значения глобальных данных посылается этому серверу в виде сообщения. Аналогичный подход применим и для физических устройств. Так, например, задача может послать данные на печать в виде сообщения, направленного к серверу принтера. 3. Запретить прерывания на время доступа к разделяемым данным. Кардинальное решение, которое, впрочем, не приветствуется в системах реального времени. 4. Использовать для упорядочивания доступа к глобальным данным семафоры. Наиболее часто применяемое решение, которое, впрочем, может привести в некоторых случаях к «инверсии приоритетов». Последний пункт стоит прокомментировать подробнее, поскольку понятие «семафор» встречается первый раз. Семафор - это как раз то средство, которое часто используется для синхронизации доступа к ресурсам. В простейшем случае семафор представляет собой байтовую переменную, принимающую значение 0 или 1. Задача, перед тем как использовать ресурс, захватывает семафор, после чего остальные задачи, желающие использовать тот же ресурс, должны ждать, пока семафор (ресурс) освободится. Существуют также так называемые счетные семафоры, где семафор представляет собой счетчик. Пусть к системе подключено три принтера. Семафор, отвечающий за доступ к функциям печати, инициализируется со значением 3, а затем каждый раз, когда какая-либо задача запрашивает семафор для осуществления печати, его значение уменьшается на 1. После завершения печати задача освобождает семафор, в результате чего значение последнего увеличивается на 1. Если текущее значение семафора равно 0, то ресурс считается недоступным, и задачи, запрашивающие печать, должны ждать, пока не освободится хотя бы один принтер. Таким образом, может производиться синхронизация доступа множества задач к группе из 3 принтеров. Так как по своей сути семафор также представляет собой глобальную переменную, все неприятности, которые упоминались ранее в связи с самолетом МИГ-29, по идее, должны поджидать нас и здесь. Однако, так как работа с семафорами происходит на уровне системных вызовов, программист может быть уверен, что разработчики операционной системы обо всем заранее позаботились. Проникнувшись сознанием того, насколько опасно изменять глобальные переменные в условиях, когда все вокруг так и норовят друг друга вытеснить, читатель, наверно, не удивится, что участки кода программ, где происходит обращение к разделяемым ресурсам, называются критическими секциями. Так как процессы обычно не имеют доступа к данным друг друга, а ресурсы физических устройств, как правило, управляются специальными задачами-серверами (драйверами), наиболее типична ситуация, когда «гонки» за доступ к глобальным переменным устраивают различные потоки, исполняемые в рамках одного программного модуля. Для того чтобы гарантировать, что критическая секция кода исполняется в каждый момент времени только одним потоком, используют механизм взаимоисключающего доступа, или попросту мутексов (Mutual Exclusion Locks, Mutex). Практически мутекс представляет собой разновидность семафора, который сигнализирует другим потокам, что критическая секция кода кем-то уже выполняется. Критическая секция, использующая мутекс, должна иметь определенные суффиксную и префиксную части. Например: Если мутекс захвачен, то поток, пытающийся войти в критическую секцию, блокируется. После того как мутекс освобождается, один из стоящих в очереди потоков (если таковые накопились) разблокируется и получает возможность доступа к глобальному ресурсу. Думаю, на этом рассмотрение средств синхронизации доступа к общим ресурсам можно закончить, хотя, разумеется, множество тем осталось за скобками. Например, в WIN 32 используется, в числе прочего, специальная разновидность мутексов под названием Critical Section Object. Необходимо также помнить, что, кроме ОС, имеющих WIN 32 или POSIX API, существует большое число ни с чем не совместимых ОС, поэтому наличие средств синхронизации и особенности их реализации должны рассматриваться отдельно для каждой конкретного МРВ. А вот возможные неприятности в борьбе за ресурсы. Смертельный захват (Deadlock). В народе побочные проявления этой ситуации называются более прозаично - «зацикливание» или «зависание». А причина этого может быть достаточно проста - «задачи не поделили ресурсы». Пусть, например, Задача А захватила ресурс клавиатуры и ждет, когда освободится ресурс дисплея, а в это время Задача В также хочет пообщаться с пользователем и, успев захватить ресурс дисплея, ждет теперь, когда освободится клавиатура. Так и будут задачи ждать друг друга до второго потопа, а пользователь будет в это время смотреть на пустой экран и ругать последними словами программистов, которые не смогли сделать нормально работающую систему. В таких случаях рекомендуется придерживаться тактики «или все, или ничего». Другими словами, если задача не смогла получить все необходимые для дальнейшей работы ресурсы, она должна освободить всё, что уже захвачено, и, как говорится, «зайти через полчаса». Другим решением, которое уже упоминалось, является использование серверов ресурсов. Инверсия приоритетов (Priority inversion). Как уже отмечалось, алгоритмы планирования задач (управление доступом к процессорному времени) должны находиться в соответствии с методами управления доступом к другим ресурсам, а всё вместе - соответствовать критериям оптимального функционирования системы. Эффект инверсии приоритетов является следствием нарушения гармонии в этой области. Ситуация здесь похожа на «смертельный захват», однако сюжет закручен еще более лихо. Представим, что у нас есть высокоприоритетная Задача А, среднеприоритетная Задача В и низкоприоритетная Задача С. Пусть в начальный момент времени Задачи А и В блокированы в ожидании какого-либо внешнего события. Допустим, получившая в результате этого управление Задача С захватила Семафор А, но не успела она его отдать, как была прервана Задачей А. В свою очередь, Задача А при попытке захватить Семафор А будет блокирована, так как этот семафор уже захвачен Задачей С. Если к этому времени Задача В находится в состоянии готовности, то управление после этого получит именно она, как имеющая более высокий, чем у Задачи С, приоритет. Теперь Задача В может занимать процессорное время, пока ей не надоест, а мы получаем ситуацию, когда высокоприоритетная Задача А не может функционировать из-за того, что необходимый ей ресурс занят низкоприоритетной Задачей С.
Дата добавления: 2014-01-20; Просмотров: 499; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |