Wed, 05 Jan 2005 06:13:21 +0300 Kirill Frolov wrote to Harry Zhurov:
KF>>> О чЯм и говорится -- ОС не нужна. Вместо того чтобы вначале заставить KF>>> исполняться N относительно независимых программ параллельно, а потом KF>>> упереться в вопросы их синхронизации, HZ>> Hет там никаких вопросов, все просто и прозрачно, для этого HZ>> средства в ОС имеются. KF> Они не для этого, они там поэтому имеются. Задача вначале порождена, а KF> потом решена. Hет ОС, нет и этих проблем.
Какая это проблема порождена? Проблема там одна (в случае вытесняющего механизма) - совместное использование ресурсов в асинхронных задачах. Ровно эта же проблема существует и безо всяких ОСей - т.е. в Foreground/Background системах, когда одни и те же ресурсы используются и в коде основной программы, и в коде прерываний! Тут ты тоже вынужден прибегать к специальным средствам - городить те же самые (по смыслу) критические секции, самодельные семафоры и прочее - и все для того, чтобы защититься от проблем из-за асинхронного доступа к ресурсам. И разница лишь в том, что в составе ОС эти средства интегрированы с ядром и помимо защиты еще участвуют в организации event-driven потока управления. Ничего искусственного, надуманного там нет.
KF>>> приоритетности исполнения, HZ>> Тоже ничего сложного. KF> Прямо как аллокатор памяти за 10 минут...
Про менеджер памяти за 10 минут - это не ко мне! Но освоить эти средства ОС - семафоры/флаги событий/мутексы/и т.д., имхо, будет куда как попроще, чем написать менеджер памяти.
KF>>> обработки прерываний -- чем собственно ОС и занимается, в данном случае, KF>>> насколько я понимаю, исключается сущность все это вопросы порождающая -- KF>>> *асинхронное* (псевдо-)параллельное исполнение программ разменивается на KF>>> изначально синхронную систему конечных автоматов, входными событиями для KF>>> которых являются, например, те же прерывания. HZ>> Ага, а время реакции как тут получать? Ась? Чтобы система конечных KF> Прерыванием. Да, я согласен, тут есть много над чем подумать. Hо такой KF> подход не только имеет право на существование, а вполне способен KF> составить конкуренцию второму варианту, с ОС внутри.
Да никто и не покушается на написание программ на голом МК! Я, в отличие от некоторых (не тебя), совершенно не утверждаю, что "без ОС никуда"! Более того, на любом МК, где ОЗУ меньше полукилобайта, реализация RTOS с вытеснением крайне затруднительна и не представляет практического интереса, т.к. все ресурсы ОЗУ на это и уйдут. Поэтому эта ниша - исключительно для писания без ОС или с использованием кооперативной ОС. Но вот когда ОЗУ уже килобайт и более, тут уже имеет смысл подумать про использование - можно сэкономить кучу сил и времени, не тратя их на достаточно тупую рутинную работу по организации кода (которая повторяется из проекта в проект). Поэтому я лишь спорю с утверждением, что "ОС в embedded не нужна" - есть случаи/варианты/условия, где она очень даже нужна (хотя всегда можно обойтись без ОСей, компиляторов, а также и ассемблеров и процессоров как таковых! Вопрос лишь: а нужно ли обходиться, если можно, воспользовавшись, решить задачу быстрее и эффективнее?).
KF> Я даже думаю, вариант предлагаемый Полянским -- одна задача в main() и KF> остальные KF> в автоматах
:) С таким же успехом можно схему включения с общим эмиттером называть "схемой Иванова" [Петрова, Сидорова] на основании того, что он (Иванов [Петров, Сидоров]) ее упоминал.
KF> -- оптимальный для небольших задач/контроллеров. В ряде случаев, при KF> изначально недетерменированном наборе задач, при наличии задач KF> преобразование алгоритма которых в форму с явно выделенным состоянием KF> затруднено (по-моему оно всегда затруднено...), такой подход оказывается KF> действительно и сложным и не рационалным. Hо отнюдь не всегда, и даже не KF> часто, Imho. И совершенно отдельный вопрос, KF> что даЯт ОС -- это интерфейс.
Про только лишь интерфейс согласен в контексте кооперативных ОС. А в случае вытесняющих - нет! Не менее важным является возможность иметь более-менее детерминированное время отклика вне зависимости от того, какая часть программы выполняется.
HZ>> проце будь добр выдать скорость прогона цикла такого автомата. Вот и HZ>> получается, что долбает вхолостую ядро даже когда делать нечего. И еще HZ>> проц HZ>> надо с высокой тактовой. KF> Автоматы можно запускать из отдельного более лЯгкого KF> "автомата-планировщика" по возникновению заранее установленных KF> событий/сигналов порождаемых другими автоматами, запускаемыми, например, в KF> прерывании.
Не, не понял! Вот есть фрагмент кода, который ждет прихода байта по UART'у, чтобы его (байт) обработать - вопрос: как передать ему (этому фрагменту кода) управление непосредственно по приходу байта при условии, что этот код находится не в обработчике прерываний? И чтобы промежуток времени от прихода байта в регистр-приемник порта до получения управления соответствующим кодом гарантировано не превышал какого-то значения. Я вижу тут только два пути - либо поместить этот код в обработчик прерываний, либо использовать ОС с вытеснением и поместить код в высокоприоритетный процесс. Какие тут автоматы и как они помогут - не понятно!
HZ>> В случае же с RTOS (вытесняющей) код работает по событиям. Когда нет HZ>> событий, проц может вообще в спячке находиться. KF> Аналогично.
Как все эти автоматы могут знать, что произошло событие? Только путем постоянного поллинга. И для лучшей времени реакции время поллинга должно быть как можно более коротким. Это не "аналогично", а совершенно перпендикулярный подход!
HZ>> И со временем реакции все определено по максимуму. В отличие от. KF> Совсем нет. Тут тебе и вопрос инверсии приоритетов, не решЯнный никак KF> во многих мелких RTOS, и просто похабная реализация планировщика.
Инверсия приоритетов - это отдельный вопрос. На мелких МК, где время занятости процесса соизмеримо со временем переключения приоритетов (при инверсии) и всего сопутствующего, в инверсии приоритетов смысла мало. Но и без нее можно оценить время реакции. Например, я знаю, что у меня наиболее приоритетный процесс получает управление при возникновении события, которое он ждет, не более, чем через 25-30 мкс (при 5 МГц тактовой МК). И обработка события занимает в нем не более 50 мкс. Значит при возникновении события для следующего по приоритетности процесса максимальное время реакции будет
25[30]+50+25[30] - порядка 100-110 мкс. И так далее. На практике редко надо вычислять время реакции для всех процессов - обычно интересуют пара-тройка высокоприоритетных, особенно тех, которые работают с аппаратурой - UART'ом, например, - он ведь ждать не будет.
И все это дает спокойно писать, используя, например, длительные вычисления - в нескольких проектах у меня требовалось каждые 100 мс производить пересчет параметров, который занимал порядка 22 мс. И в той же программе работает протокол обмена пакетами через UART, переключение разрядов цифрового индикатора (динамическая индикация) - надо раз в 4 мс циферку переключить, опрос клавиатуры и проч.
Так вот, затолкав это длинное вычисление в низкоприоритетный процесс, а протокол обмена, индикатор и клавиатуру в высокоприоритетные, получил, что надо. И код выглядит простым и прозрачным и в случае вычислений, где последовательно выполняется вычисление пачки полиномов в цикле, и в случае протокола обмена, где алгоритм тоже прописан линейно - послал пакет, встал на ожидание с таймаутом, если дождался ответа, идем дальше, если отвалился по таймауту, повторил в цикле несколько раз, если все разы ответа не получил, метнул сообщение процессу, выводящему на индикатор, что, дескать, внешний девайс не отвечает.
А в случае писания этого на голом МК с помощью автоматов состояний (более прежние версии этого софта были реализованы именно так, т.ч. прекрасно понимаю, о чем ты говоришь), имел гору запутанного кода - делал и с помощью switch'а, и с помощью массивов указателей на функции, и с помощью виртуальных функций, когда С++ стал доступен - это, конечно, наиболее приятный, читабельный и безопасный способ (по сути те же массивы указателей на функции, только обернуто все это в класс и за правильностью и соответствием следит компилятор). И вычисления приходилось разбивать на тучу состояний так, чтобы функция за один вызов занимала времени не более 800 мкс (иначе можно байтик с UART'а пропустить и индикатор начинал мерзко подмаргивать). Т.ч. очень хорошо представляю себе тот и другой способы написания программы - благо делал это не раз.
HZ>> Да, за это цена заплачена - ОЗУ надо иметь какое-то для стеков HZ>> процессов, KF> AT90S1200 тут выглядит особенно замечательно, вкупе с x51 клонами, PIC16 KF> и любыми контроллерами с небольшим объЯмом ОЗУ.
Тут не над чем думать - на S1200, на PIC16 вытесняющая многозадачность не реализуема (во всяком случае, я не знаю, как это можно сделать.). На первом совсем нет ОЗУ (а его надо, напомню, по моим оценкам не менее полукилобайта, иначе это баловство), а у второго конкретные проблемы с косвенной адресацией и, главное, со стеком. А вот на PIC18 уже выходит прилично, чему есть и реальные подтверждения, причем и среди работ подписчиков этой эхи.
KF> Да и отдельный вопрос -- сколько этого ОЗУ нужно для каждой задачи в KF> частности, и для системы в целом. Заранее это выяснить -- нетривиальная KF> задача.
Она не такая сложная. Стек для задачи должен быть достаточным для сохранения в нем контекста задачи, переменных задачи, адресов возврата и некоторого запаса - процентов 20-30. Например, если у MSP430 контекст занимает
30 байт, переменные какой-то задачи - 20 байт, глубина вложенности вызовов -
10+прерывание - 12 -> 12*2 = 24 байта, то 30 + 20 + 24 = 74 + запас - байт 100 уже будет достаточно. Единственное, что нужно не забывать корректировать размер стека задачи при изменении функциональности этой задачи - я наступал на эти грабли: добавил массив, а стек не изменил - сразу стало падать. Но и обнаружилось сразу при первом же анализе.
HZ>> И писание проги под RTOS - занятие куда более быстрое и приятное, чем без HZ>> оной. KF> Равно как и писание под настольный компутер куда более быстрое и KF> приятное занятие...
Ты сравниваешь несравнимое - на МК можно написать одну и ту же программу и так, и эдак, соответственно, можно более-менее объективно сравнить плюсы и минусы. А для настольного компа ты пишешь совершенно другую программу, поэтому сравнивать тут преимущества и недостатки довольно бессмысленно.