Dr. ir. M. Timmerman
Royal Military Academy, Renaissancelaan 30, B-1000 BRUSSELS
Real-Time Consult, Rue de la Justice 23, B-1070 BRUSSELS
Email: [email protected] URL: http:www.realtime-info.be
ir. J-C. Monfret
Real-Time Consult, Rue de la Justice 23, B-1070 BRUSSELS
Email: [email protected] URL: http:www.realtime-consult.com
Перевод с англ.
Все больше компаний пытается использовать Windows NT как стандартную ОС на всех уровнях индустриальной иерархии. Использование ее как сервера или рабочей станции понятно, но встречаются попытки использовать ее непосредственно в производственном процессе. Однако установка "в цехе" требует, чтобы ОС работала в режиме реального времени. Удовлетворяет ли Windows NT этому требованию?
Вначале мы определим, что такое ОС реального времени и какие характеристики должна иметь ОС, чтобы на ее базе можно было построить систему реального времени. Будут введены понятия жесткой и мягкой системы реального времени. Во второй части мы показываем как и почему Windows NT не удовлетворяет требованиям, предъявляемым жесткими системами реального времени. Мы покажем однако, что в некоторых простых мягких системах реального времени Windows NT может использоваться при некоторых обстоятельствах.
При проектировании Windows NT требования, предъявляемые к ОС реального времени (ОСРВ) не учитывались: она спроектирована как многоцелевая ОС (МОС) или, более точно, как сетевая ОС (СОС). Тем не менее, в силу того, что Windows NT создавалась разработчиками ОС VMS, в нее включены элементы системы реального времени. Например Microsoft ввела понятие класса процессов реального времени. Они диспетчеризуются таким же образом как это было бы в ОСРВ. Механизм прерываний ISR (Interrupt Service Routine) также реализован очень эффективно [1]. Однако позволяет ли это классифицировать Windows NT как ОСРВ?
Система реального времени (СРВ) должна давать отклик на любые непредсказуемые внешние воздействия в течение предсказуемого интервала времени. Для этого должны выполняться следующие требования:
Ограничение времени отклика. Т.е. после наступления события реакция на него гарантированно последует до предустановленного крайнего срока. Отсутствие такого ограничения рассматривается как серьезный недостаток программного обеспечения.
Например, не считается недостатком программы медленная реакция текстового редактора, раздражающая оператора. Эта задержка связана только с производительностью и, скорее всего, может быть устранена переходом на более быстрый процессор. Однако, можно показать, что использование более быстрого процессора не снимает проблемы отсутствия ограничения на время отклика [2].
Одновременность обработки: даже если наступает более одного события одновременно, все временные ограничения для всех событий должны быть выдержаны. Это означает, что системе реального времени должен быть присущ параллелизм. Это достигается использованием нескольких процессоров в системе и/или многозадачного подхода.
Хорошим примером жесткой системы реального времени является бортовая система самолета проверки электрических соединений в полете.
Примерами являются торговый автомат и подсистема сетевого интерфейса. Во втором случае вы можете восстановить отсутствующий пакет, используя тот или иной сетевой протокол для повторной пересылки. Естественно, при этом снижается производительность системы.
Другими примерами систем реального времени являются системы управления атомными электростанциями или технологическими процессами, медицинского мониторинга, управления вооружением, космической навигации, разведки, управления лабораторными экспериментами, управления автомобильными двигателями, робототехника, телеметрические системы управления, системы антиблокировки тормозов, системы сигнализации - список бесконечен.
Различие между жесткой и мягкой СРВ зависит от требований к системе - система считается жесткой, если "нарушение временных ограничений не допустимо" и мягкой если "нарушение временных ограничений не желательно". Ведется множество дискуссий о точном смысле терминов "жесткая" и "мягкая" СРВ. Можно даже аргументировать то, что мягкая СРВ не является СРВ вовсе ибо основное требование соблюдения временных ограничений не выполнено. В действительности термин СРВ часто неправомерно применяют по отношению к быстрым системам. В этом случае под "быстрой системой" понимается мягкая СРВ. Поэтому
Мы определяем ОСРВ как ОС, которая может использоваться для построения жесткой СРВ.
Часто путают понятия СРВ и ОСРВ, а также неправильно используют атрибуты "мягкая" и "жесткая". Иногда говорят, что та или иная ОСРВ мягкая или жесткая. Нет мягких или жестких ОСРВ. ОСРВ может только служить основой для построения мягкой или жесткой СРВ. Сама по себе ОСРВ не препятствует тому, что ваша СРВ будет мягкой. Например, если вы решили создать СРВ, которая должна работать через Ethernet по протоколу TCP/IP. Такая система не может быть жесткой СРВ, поскольку сама сеть Ethernet непредсказуема. Разумеется, если вы решили создать приложение на базе ОС вроде Windows 3.11, ваша система никогда не будет жесткой СРВ, ибо поведение самой "ОС" никоим образом не является предсказуемым.
Как указывалось выше, ОСРВ должна быть предсказуемой. Это означает не то, что ОСРВ должна быть быстрой, а то, что максимальное время выполнения того или иного действия должно быть известно заранее и должно соответствовать требованиям приложения. ОС Windows 3.11 даже на Pentium PRO 200 MHz бесполезна для ОСРВ, ибо одно приложение может захватить управление и заблокировать систему для остальных. Первое требование состоит в том, что ОС должна быть многонитевой на принципе абсолютного приоритета (прерываемой). То есть, планировщик должен иметь возможность прервать любую нить и предоставить ресурс ните, которой он более необходим. ОС (и аппаратура) должны также обеспечивать прерывания на уровне обработки прерываний.
Проблема в том, чтобы определить какой задаче ресурс требуется более всего. В идеальной ситуации ОСРВ отдает ресурс нити или драйверу с ближайшим крайним сроком (мы называем это ОС, управляемой временным ограничением (deadline driven OS), см. также [2]). Чтобы реализовать это, ОС должна знать сколько времени требуется каждой из выполняющихся нитей для завершения. До сих пор не существует ОС, построенной по этому принципу, так как он слишком сложен для реализации. Поэтому разработчики ОС принимают иную точку зрения: вводится понятие уровня приоритета для задачи, и временные ограничения сводят к приоритетам. Так как умозрительные решения чреваты ошибками, показатели СРВ при этом снижаются. Чтобы более эффективно осуществить указанное преобразование ограничений, проектировщик может воспользоваться теорией расписаний [2] или имитационным моделированием [9], хотя и это может оказаться бесполезным. Тем не менее, так как на сегодняшний день не имеется иного решения, понятие приоритета нити - неизбежно.
Так как задачи разделяют данные (ресурсы) и должны сообщаться друг с другом, представляется логичным, что должны существовать механизмы блокирования и коммуникации.
На самом деле, именно этот механизм синхронизации и тот факт, что различные нити используют одно и то же пространство памяти, отличают нити от процессов. Процессы не разделяют одно и то же пространство памяти. Так например, старые версии UNIX не являются многонитевыми. Старый UNIX - многозадачная ОС, где задачами являются процессы, которые сообщаются через потоки (pipes) и разделяемую память. Оба эти механизма используют файловую систему, а ее поведение - непредсказуемо.
Комбинация приоритета нити и разделение ресурсов между ними приводит к другому явлению - классической проблеме инверсии приоритетов. Это можно проиллюстрировать на примере, где есть как минимум три нити. Когда нить низшего приоритета захватила ресурс, разделяемый с нитью высшего приоритета, и начала выполняться нить среднего приоритета, выполнение нити высшего приоритета будет приостановлено, пока не освободится ресурс и не отработает нить среднего приоритета. В этой ситуации время, необходимое для завершения нити высшего приоритета зависит от нижних приоритетных уровней, - это и есть инверсия приоритетов. Ясно, что в такой ситуации трудно выдержать ограничение на время исполнения.
Чтобы устранить такие инверсии ОСРВ должна допускать наследование приоритета, т.е., повышение уровня приоритета нити до уровня нити, которая ее вызывает. Наследование означает, что блокирующая ресурс нить наследует приоритет нити, которую она блокирует (разумеется, это справедливо лишь в том случае, если блокируемая нить имеет более высокий приоритет).
Иногда утверждают, что в грамотно спроектированной системе такая проблема не возникает. В случае сложных систем с этим нельзя согласиться. Единственный способ решения этой проблемы состоит в увеличении приоритета нити вручную прежде, чем ресурс окажется заблокированным. Разумеется это возможно в случае, когда две нити разных приоритетов претендуют на один ресурс. В общем случае решения не существует.
Наконец, следует рассмотреть временные ограничения. Времена выполнения системных вызовов и временные характеристики поведения системы в различных обстоятельствах должны быть известны разработчику. Поэтому производитель ОСРВ должен приводить следующие характеристики:
Когда все указанные характеристики ОС известны, можно представить себе разработку СРВ на ее базе. Естественно, требования по производительности к разрабатываемой системе должны быть согласованы с возможностями выбранной ОСРВ и аппаратуры.
Ясно, что Windows NT многонитевая ОС с абсолютным приоритетом [3] и как таковая удовлетворяет требованию 1. Проанализируем насколько она предсказуема. Тут необходимо вспомнить структуру Windows NT и уяснить себе могут ли и как аспекты СРВ быть воплощены в Windows NT.
В СРВ работы имеют различные приоритеты. Более критичные по времени получают более высокий приоритет. Другие же, например, отображение состояния системы, регистрация событий в файл или конфигурирование системы имеют более низкий приоритет. Чтобы учитывать эти различия, ОС должна уметь приписывать различные приоритеты этим работам.
В Windows NT понятие приоритета весьма сложное:
Имеется два класса приоритетов для процессов - класс реального времени и динамический класс. Процессы класса реального времени имеют фиксированный приоритетный уровень, который может быть изменен только в приложении, тогда как приоритеты процессов динамического класса меняются планировщиком в зависимости от типа работы, выполняемой процессом (интерактивный или не интерактивный). Только первый класс предсказуем и потому может быть использован в СРВ. Следует отметить, что для не требующей выполнения в реальном времени заявки в СРВ можно использовать второй класс, поскольку он не разделяет ресурсов с процессами класса реального времени.
Процесс имеет базовый приоритетный уровень, который может быть изменен только самим приложением.
Приоритет нити в процессе лежит в диапазоне +-2 к уровню базового приоритета и еще может принимать два граничных значения приоритета класса. Например, нити процесса с базовым уровнем приоритета 24 (класс реального времени) могут иметь приоритеты от 22 до 26, а также 16 и 31.
Итак, поскольку есть понятие приоритета нити, требование 2 формально выполнено. Однако, имеется одна проблема: приоритетных уровней мало. Большинство современных ОСРВ допускают по крайней мере 256 приоритетов. Почему это проблема? Ответ очевиден: чем больше приоритетов - тем более предсказуема система. Лучший способ при проектировании системы - приписать отдельный приоритет каждой нити [2]. Процессу в Windows NT предоставляется только 5 (7 с учетом граничных) приоритетных уровней для нитей. Поэтому многим из них придется делить один и тот же уровень. Предсказуемость будет весьма невысокой, если нужно будет обрабатывать более одного или двух критических событий. Можно возразить, что это могут делать разные процессы. Но и тогда общее число приоритетов - лишь 16. Кроме того, время переключения контекста между нитями из разных процессов много больше, чем между нитями одного процесса, ибо они функционируют в разных адресных пространствах (общее пространство памяти - атрибут контекста). Таким образом, Windows NT дает не лучшее решение.
Как говорилось выше, инверсия приоритетов является классической проблемой для СРВ. Поэтому в ОСРВ синхронизирующие систему механизмы: совместное блокирование (mutex), семафоры, критические участки кода (critical sections) должны учитывать наследование приоритета. В Windows NT это НЕ РЕАЛИЗОВАНО [4], поэтому требование 4 не выполнено. Другая проблема, связанная с инверсией приоритетов в Windows NT, обусловлена особенностями реализации некоторых системных вызовов, относящихся к GUI. Они обрабатываются синхронно (вызвавшая нить приостанавливается до завершения системного вызова) процессом, не принадлежащим классу процессов реального времени [5]. Значит нить более низкого приоритета из класса реального времени может задержать выполнение более приоритетной.
Как мы установили, относительно небольшое число приоритетов, приводящее к проблеме инверсии приоритетов, делает Windows NT пригодной разве лишь для простых СРВ (с небольшим числом типов событий).
Зачем нужна Windows NT? Как упоминалось выше, было бы желательно иметь одну и ту же ОС на всех уровнях индустриальной иерархии компании. Другой интересный кандидат на эту роль - богатая возможностями и мощная система Win32 API. Здесь имеется множество хороших платформ для разработки, компиляторов, причем существует масса специалистов, которым она хорошо знакома. Возможности ее многочисленны. Здесь есть все для создания многонитевых приложений. Осталось выяснить можно ли создавать в Win32 API приложения реального времени.
Для этого система должна быть предсказуемой и независимой от числа объектов в системе.
Для измерений мы провели несколько простых тестов. Мы создали процесс, принадлежащий классу реального времени, который имел нить, выполняющую синхронизирующие системные вызовы. Мы использовали системный вызов QuerryPerformanceCounter до и после каждого синхронизирующего вызова для измерения времени его выполнения. В конце мы сохранили все результаты на диске для обработки в Excel.
Мы убедились, что в течение теста не было своппинга и никакой ресурс не был заперт. Мы также измерили задержку, обусловленную измерениями, и вычли ее из результата. Тесты были выполнены на Pentium 100 с 24MB RAM.
Например, для системного вызова типа "совместная блокировка" мы получили среднее время выполнения 35 мксек. При этом максимальное время (однажды) достигло 670 мксек.
Почему? Эти задержки были следствием прерываний либо от диска либо от сети (тестируемая машина была подсоединена к сети), так как иных видов деятельности не было. Мы воспроизводили ситуацию много раз, искусственно загружая машину передачами на диск и в сеть. В итоге удалось получить времена задержки системных вызовов до нескольких миллисекунд!!!
Как уже говорилось Win32 API очень мощная система, но, нужно заметить, она не предназначена для работы в реальном времени. Например, очередь запросов совместной блокировки организована по правилу FIFO, а не по приоритетам [10]. Это существенный недостаток с точки зрения предсказуемости. Следует соблюдать осторожность и в отношении того, какие системные вызовы лучше использовать. Например, для синхронизации нитей внутри одного процесса механизм критических участков кода более предпочтителен по сравнению с другими (вызов этого типа выполняется за несколько микросекунд, а не 35 мксек как совместная блокировка). Этот вызов предназначен для использования именно в данной ситуации. Эта быстрота не удивительна, поскольку переключение контекста нитей внутри процесса намного проще, чем между процессами.
Последнее замечание относительно Win32 API: при использовании системных вызовов API следует иметь в виду, что некоторые из них выполняются процессами более низкого приоритета (из динамического класса) и являются синхронными. То есть, вызывающая нить будет ждать завершения вызова. Это ведет к инверсии приоритетов.
После описанных тестов мы пришли к заключению, что несмотря на мощный API, основное ядро и администратор ввода/вывода не приспособлены для обработки событий прикладного уровня в режиме реального времени!
Ниже мы обсудим, можно ли решить эту проблему на уровне драйверов.
СРВ взаимодействует с внешним миром через аппаратуру компьютера. Внешние события, поступающие в систему в виде прерываний, обрабатываются драйверами устройств.
Рис. 4 в документации DDK [6] показывает, как Windows NT взаимодействует с аппаратурой. Доступ к аппаратуре возможен только через драйвер устройств ядра. Это логично в такой ОС, ибо процессы функционируют в различных адресных пространствах и не имеют прямого доступа к устройствам. Так как большинство приложений реального времени имеет дело со специфическими внешними событиями, разработчикам приходится писать драйверы устройств ядра, чтобы обеспечить доступ к аппаратным средствам. Посмотрим как устроен драйвер устройства.
Драйвер устройства отвечает за обработку прерывания, генерируемого устройством, которым он управляет. Чтобы повысить ответственность ОС за обработку был разработан оригинальный механизм. Прерывания обрабатываются в два этапа. Во-первых прерывание очень быстро обрабатывается ISR. После этого работа завершается выполнением процедуры DPC (Deffered Procedure Call). Это порождает следующую последовательность событий:
Как мы видим, обработка прерываний в Windows NT достаточно сложна. При этом ISR должна работать как можно быстрее. Поэтому большинство драйверов выполняют большую часть работы в DPC (который может прерываться только ISR), замедляя работу других DPC, так как все они обрабатываются на одном приоритетном уровне.
Документация на драйверы устройств Windows NT говорит, что "ISR может прерываться ISR более высокого приоритетного уровня и теми DPC, которые имеют более высокий приоритет, чем пользовательская и системная нити". Но так как все DPC имеют один и тот же приоритетный уровень и так как при проектировании драйвера устройства следует делать ISR как можно короче, перенося большую часть работы в DPC, при выполнении вашему DPC придется ждать пока не будут завершены все остальные DPC. Поэтому ваше приложение будет зависеть от драйверов устройств, обслуживающих другие приложения.
Устроено ли это по разному в разных ОСРВ? Естественно, это так. Разработчик ОСРВ вначале должен выяснить на каком приоритете работают другие драйверы устройств. Обычно имеется некоторая свободная память сверх занимаемой стандартными драйверами. Вся критическая работа выполняется в ISR, и у разработчика остается возможность сконфигурировать драйвер в зависимости от временных ограничений приложения. В Windows NT ISR очень быстрая, поэтому прерывания не блокируются надолго, однако ISR делает очень мало работы. Большая часть работы перекладывается на DPC. Поэтому, если вы используете плохо написанный драйвер, вы в конце концов нарушите временные ограничения по крайним срокам, если конечно вы не последуете стратегии Microsoft и не станете выполнять всю работу в ISR (но тогда зачем вообще нужна ОС?).
Заметим, что решающим может оказаться то, что некоторые DPC от жесткого диска, как мы установили, могут выполняться в течение нескольких миллисекунд.
Другим моментом, который необходимо учитывать при проектировании СРВ, является управление памятью ОСРВ. В Windows NT все процессы функционируют в своих адресных пространствах. Это может быть достигнуто только с использованием страничной виртуальной памяти. Это очень хорошо для бизнес-приложений, но для СРВ, которая должна реагировать на внешние события в течение предсказуемых интервалов времени, это порождает неопределенность в момент, когда система должна получить страницу памяти с диска. Поэтому Windows NT дает возможность запирать страницы в памяти с помощью вызова функции VirtualLock. Но даже если это имеет место, Windows NT все равно может отпирать страницы не активного процесса и переписывать их на диск [7].
Является ли это проблемой? Нет, когда приложения хорошо спроектированы и не берут больше памяти, чем физически присутствует на машине.
Однако на уровне драйвера устройства своппинг может быть исключен.
При попытке использовать ОС для проектирования СРВ или встраиваемых систем еще несколько вопросов нуждаются в рассмотрении:
Последнее по порядку, но не по важности: следует учесть, что некоторые компании предлагают решения как приспособить Windows NT для работы в реальном времени - решение, если оно и существует, не реализовано в оригинале. По всей вероятности это свидетельствует о существовании спроса на такую доработку.
Мы показали в данной работе, что Windows NT в своем оригинальном виде, ориентированном главным образом на классические приложения, не являются хорошей платформой для приложений реального времени:
Так почему же некоторые утверждают, что могут использовать Windows NT для приложений реального времени [8]? Во-первых, одно удачное применение еще не причина для обобщений. Во-вторых, Windows NT можно использовать только в следующих случаях:
Последний пункт делает бессмысленным использование ОС.
Но в случае жестких СРВ даже не стоит поднимать вопрос об использовании Windows NT. Ваша система никогда не будет предсказуемой. Можно со всей определенностью сказать, что Windows NT не будет использоваться в ближайшем будущем ни в каких жестких СРВ!
Но что по серьезному следует изменить в Windows NT, чтобы стало возможным ее использование в жестких СРВ? Класс процессов реального времени должен иметь большее число приоритетов. Проблема инверсии приоритетов должна быть решена. Должна быть перестроена вся система прерываний:
Желает ли Microsoft и готова ли улучшить таким образом Windows NT или она считает рынок слишком маленьким, чтобы допускать на него третьи стороны?
© НАУЧНЫЙ ЦЕНТР "НАУЦИЛУС" Email: [email protected]
WEB: www.nautsilus.ru
119899, Москва, Воробьевы горы, НИИЯФ МГУ, корп. ВЭ, к.415, 315.
Тел.(095)939-5872, (095)939-3924 Факс.(095) 939-5002