Вопрос про многопоточность (МП)
- Войдите на сайт для отправки комментариев
Вопрос про многопоточность (МП).
Добрый день.
Есть потребность в организации работы нескольких задача на ATmega328:
- ввод данных с энкодера,
- вывод данных на экран,
- работа по сети (rs485).
Насколько реально реализовать эти задачи в МП режиме, да и вообще насколько подобный микроконтроллер уместен для МП (не принимая во внимание примеры с миганием 2-3 светодиодов с разной частотой) ?
Да-да-да я понимаю что это можно реализовать через проверки подсчеты времени (аля вездесущие примеры мигании светодиодами), но хочется жить проще и добавлять задачи на микроконтроллер по мере развития проекта.
Так же я не горю желанием использовать МП через «конечные автоматы» (protothread) по этому в качестве МП я рассматриваю вариант:
- с вытесняющей МП (через таймер)
- или коопертивной МП.
Причем как я понимаю в обоих вариантах придется под каждый поток формировать свой стек.
У меня не большой опыт программирования микроконтроллеров и вот что меня смущает:
Если взять библиотеку «AVR Threads» то в примере авторы выделяют под один поток стек в 128 байт для друго 512 байт, что как то жирно с учетом того что в ATmega328 2k SRAM.
Сколько в среднем по больнице глубина стека в типичных приложениях ?
А если нужно 4-5 потоков ? Подключать внешнею SRAM, на подобие 23K256 и там хранить стеки и увеличивать квант времени для потока ? Но это уже монстр получается :(
Кооперативная МП смущает тем что при написание алгоритма надо будет все время помнить о передаче управления следующему потоку, да и опять же вопрос со стеком :(
«Как сделать так что бы ничего не делать» ?
Нужно просто включить ГОЛОВУ и отойти от концепции "скетчей" и написать всё самому ... да хоть на... С(++) и тгда будет счЯсЬе )))
))) могу дать "скетч" мигания 12-ю светодиодами с ШИМ-модуляцией+дисплей+джойстик,правда почти весь на ASM )))
Безусловно я согласен с Вашей концепцией о включение головы.
Но в то же время хотелось бы воспользоваться опытом людей прошедшие этот путь, почему бы и нет ?
За код спасибо, но было бы просто мего-супер если бы Вы обрисовали концепцию того как вы это реализовали. Машина-состояний ? Поделитесь пожалуйста опытом :)
Вот личный вариант. Но "многопоточность" там своеобразная. http://arduino.ru/forum/programmirovanie/tsifrovye-avtomaty-v-klassakh-p...
Но в то же время хотелось бы воспользоваться опытом людей прошедшие этот путь, почему бы и нет ?
Невозможно воспользоваться чужим опытом, не имея своего.
PS. А многозадачность "по таймеру" для МК идея безусловно вредная: если мы говорим о пользовательской системе типа Windows, частота прерываний определяется характеристиками человека. МК в основном общается не с человеком, а с периферийными устройствами, характерные времена для которых могут лежать в очень широких пределах. Соответственно, и выбрать квант времени пригодный хотя бы для большей части задач просто не получится.
Насколько я понял, это из области автоматов.
Данная идея меня смущает необходимость переосмысливать подход в реализации алгоритмов: вместо традиционного подхода делать все последовательно, придется описывать алгоритм через состояния, заводить флаги состояний, все это как то контролировать.
Уж простите, но хочется удобства и если есть возможность писать традиционный код хоть и с потерей времени на переключение контекста я готов потерпеть.
Когдато тоже пытался http://arduino.ru/forum/programmirovanie/ochered-sobytii
Tucoso - поменяйте классическую ардуину на СТМ32-дуину с 20К SRAM и запустите на ней RTOS
я юзаю самописные таймеры + очередь сообщений.
RTOS вполне реализуется даже на НАНО .. только это не поможет ТС-у ни разу.
Когда мне нужно сделать что-то реально параллельно, я просто ставлю отдельный МК на каждый поток. В результате проблема многозадачности вырождается в проблему связи между МК, которая в моих проектах намного проще, т.к. не ахти как много им надо общаться. При нынешней цене на МК (особливо на PIC, да и на AVR тоже), вполне себе решение. Тем более для хоббийных задач, когда не нужно усираться, чтобы было на копейку дешевле, чем у конкурентов.
Это уже многоядерность, однако. ;)
RTOS вполне реализуется даже на НАНО .. только это не поможет ТС-у ни разу.
тебе реально нужно параллельное выполнение?
Да, я очень хотел бы все сделать в потоках.
Уж простите, но хочется удобства и если есть возможность писать традиционный код хоть и с потерей времени на переключение контекста я готов потерпеть.
То, что сейчас есть в МК - и есть самый что ни на есть традиционный код. В отличие от большинства современных наворотов.
Контроллер спроектирован так, чтобы выполнять единственную задачу и только в этом случае он может работать хорошо. Хотя бы потому, что может напрямую работать с пенриферией.
Как только у нас появляется многозадачность, сразу возникает необходимость изолировать задачи от "железа". Дабы избежать конфликтов. А это ресурсы, и немалые.
А в еще большей степени - граничения. Причем - очень существенные. На ПК мы можем мириться с этими ограничениями только потому, что существуют МК, у которых этих ограничений нет. И именно многообразная периферия, работающая на МК и подключаемая к ПК, дает возможность решать реальные задачи на ПК, не замечая этих ограничений.
... т.е. поток каждый из 5ти потоков будет прерыватся на 35х4=140 микросекунд. По мне так комфортно время, но может я и ошибаюсь, поправте.
Если не хочешь менять подход - подтягивай железо до уровня привычного.
Законы эволюции никакая каменноголовая дума пока не изменила: изменяйся или вымрешь.
Законы эволюции никакая каменноголовая дума пока не изменила: изменяйся или вымрешь.
Некоторые как-то странно эти законы понимают. Например, динозавры, похоже, считали, что в естественном отборе главное не победа, а участие - олимпийцы, блин. (Хотя, те, кто не поленился прочитать Олимпийскую Хартию от начала и до конца, те знают, что она вовсе не про победу и участие, а совсем про другие материи :)))
Tucoso, вот простенькийц пример: https://code.google.com/archive/p/arduino-tvout/
Здесь 8-разрядный микроконтроллер с тактовой частотой 16 МГц без всякой суперскалярности и пр. формирует видеосигнал разрешением 128х96 пикселей.
По пропорции ПК с процессором на 3.2 ГГц должен быть способен сделать подобное, но уже с разрешением 1920х1280.
Попытайтесь написать приложение под Windows, которое формировало бы аналоговый видеосигнал в таком разрешении.
Вот Вам и ответ на вопрос: а нужно ли пытаться имитировать на МК возможности, имеющиеся на ПК.
https://www.youtube.com/watch?v=9JmTvSu9sG8
RTOS вполне реализуется даже на НАНО .. только это не поможет ТС-у ни разу.
Да, я очень хотел бы все сделать в потоках.
1. Забудьте про JAVA и все её навороты при работе с микроконтроллерами. Стоимость их реализации не перевешивает удобства и полезности ни в одном глазу (тут сейчас начнут спорить недокодеры).
2. Потоки в JAVA это реализация класса Threads, который в реальных многопоточных/многоядерных и пр. системах опирается на реализацию ОС - все те же потоки, семафоры, сигналы и мьютексы. То есть, это "надстройка" снижающая "уровень вхождения" за счет потери производительности. Впрочем вся жаба предназначена именно для этого. (тут можете опять спорить, мне - без разницы).
3. Да, на переключение контекста в AVR (не только 328p, практически любой МК AVR) потребуется сохранить-восстановить контекст, который имеет 32 РОН + SREG + TIMSK + мелочи по поиску адреса, установления стека и т.д. Итого около 34 операций чтения-записи в память, каждая по 2 такта. 34*2*2 = 136 тактов. То есть оценка в 160 тактов - близка к истине, если смена контекста прописана оптимально. Кое что можно "упростить" но не более чем до 80-100тактов, учитывая "особенности компилятора" (непереносимо в будущее).
4. 400 команд это не 400 тактов как Вам показалось. В среднем в потоке команды чтения/записи в память составляют около 1/3, а они все .. по 2 такта. Также все команды, имеющие "операнд" в команде (2 слова) тоже работают по 2 такта. То есть 400команд это "в среднем" 600-700 тактов ЦП. Впрочем, не суть важно.
5. На одном ядре можно сделать только вытесняющую многопоточность. И если у Вас 4 потока, то каждый поток будет ждать не *4, а *3 (N-1 -- ждем остальных, кроме себя) единиц времени исполнения потока. В больших ОС (жаба - привет!) время исполнения потока как правило нормировано и составляет 1 миллисекунду (к вопросу "Вас устраивает 35 мксек"). На AVR многопоточность удобно размещать на таймере .. watchdog, но он умеет работать не шустрее .. 8мсек. Удобно тем, что он автоматом вызывает "сброс" МК на нулевой адрес, где и стоит размещать "диспетчер задач".
6. Количество потребного стека оценивается достаточно просто, ибо в нем храняться исключительно: а) адреса возврата из вызванных процедур вложенно, б) все параметры вложенных вызовов, не входящие в "регистры-параметров" компилятора и в) все локальные переменные вложенных вызовов не влезшие в регистровое поле МК. Всё, ничего иного там нет. Соответственно, раз Вы имеете "опыт разработки инженерных решений" (в чем я лично сомневаюсь), то Вам не составит труда оценить потребный размер стека под каждый свой поток. Но .. я сильно сомневаюсь, если читать то что Вы написали уже.
7. Диспетчер задач - в общем-то примитивный алгоритм, и для его решения есть готовые наброски в виде setjump(), longjump() .. ознакомьтесь. В принципе, возможно создание диспетчера, который контекст будет хранить .. на стеке самого потока. Тут уже было обсуждение такого решения.
8. Сколько задач "потянет Мега"? (Нано, УНО .. они все едины практически с этой кочки зрения - 16Мгц и AVR) .. В среднем, процедура обработки и управления тем или иным устройством в моей практике не превышает макс .. 100 команд. Плюс процедуры вычислений тех или иных моментов .. тут сложнее. Ещё сложность в том, что чтение окр. среды происходит по большей части .. по прерываниям, что само по себе "элемент многозадачности и потоков" .. аппаратный.
9. Разработка многопоточного приложения де факто мало чем отличается от .. автоматного стиля для конечных автоматов. Там все ровно тоже самое: есть КА (поток), который получает данные извне (слушатель КА) и делает нечто, в общем-то наплевав на остальные КА в системе. Если требуется он может "сообщить" состоянием (семафором, послать сигнал потоку) другому КА, что тому следует сделать .. все ровно тоже самое.
Ну вот как-то из этих соображений и следует действовать далее. :)
Если не хочешь менять подход - подтягивай железо до уровня привычного.
Законы эволюции никакая каменноголовая дума пока не изменила: изменяйся или вымрешь.
Я приношу извинения, но почему так часто люди любят давать результирующею оценку без фактуры - "изменяйся или вымрешь". Кто то из комментаторов сказал, что да, мол многопоточность в МК не реализуема, она не будет работать, а если будет то % полезного времени на код будет ниже плинтуса ? А я тут все ною и ною, дайте мне многопоточность!
Да вполне реализуемо. И осцилограф вполне монстрячиться и с отдельным потоком на вывод и с памятью тоже легко пилиться и многое иное делается, чего "не бывает" .. Ви знаете .. 16 мегагерц это о-очень много! Это практически IBM PC AT x286 в "спичечном коробке" .. а там и не такое выделывали.. ;)
Если не хочешь менять подход - подтягивай железо до уровня привычного.
Законы эволюции никакая каменноголовая дума пока не изменила: изменяйся или вымрешь.
Я приношу извинения, но почему так часто люди любят давать результирующею оценку без фактуры - "изменяйся или вымрешь". Кто то из комментаторов сказал, что да, мол многопоточность в МК не реализуема, она не будет работать, а если будет то % полезного времени на код будет ниже плинтуса ? А я тут все ною и ною, дайте мне многопоточность!
Ну обыкновенный Линукс как-то же пищит, рисует и в сеть пуляет вполне себе .. с дискретностью потока в 1мсек .. :) Идаже делал это ещё на 386-м проце, который тоже далеко не "гигагерцовый" .. может проблема не в гигагерцах или "новизне камня" (возьмите СТМ32..) а в кривых ручонках, что действительно "тащат с ПК" кучки гумна на микроконтроллеры, даже не понимая сколько и чего там помазано поверх того, что реально работает в коде (1-3% от объема)? :)
И это, как-то не обнаружил аплодисментов в теме за осцилограф с частотой сьема 592 килогерца .. не обманывайте вьюношу .. :)
Однако, если запузырите такую многозадачность, чтобы и сенсоры (обмен данными с которыми прерывать зачастую нельзя) успевали и экранчики рисовали веселые картинки и сеть пуляла байты во все стороны - я только поапплодирую.
И я.
Давайте не забывать, что Линукс не процессором пуляет в сеть, а сетевушкой за $10, как минимум. Которая и буферизует и ошибки обрабатывает и контрольные суммы считает, да и много чего другого. И показывает Линупс отдельной видеокартой... и пр. и др.
Только в сетевушку и видеокарту тоже все это пулять необходимо и с не меньшей скоростью .. и на той же EGA особо не разбежишься, а 16 кадров в сек она пуляла даже на 286-м. А пищать Линукс так умеет и вовсе встроенным динамиком и изначально умел. В общем-то "параллельно". :)
Arhat109-2
Однако, если запузырите такую многозадачность, чтобы и сенсоры (обмен данными с которыми прерывать зачастую нельзя) успевали и экранчики рисовали веселые картинки и сеть пуляла байты во все стороны - я только поапплодирую.
Я обещаю выложить результаты какие бы они не были :)
С видео не разбирался особо, но в сетевой адаптер не нужно постоянно пулять непрерывным потоком. Есть процессорное время - закинул в буфер / прочитал из него, нет - абонент подождет. Если бы всё было шоколадно и без сетевушек - никто бы не стал делать специализированные разгружающие чипы. Впрочем, думаю, Вы и сами понимаете, что бесконечно на лошадь грузить нельзя - хоть ее Буцефалом назови, хоть Линуксом.
Конечно, если рассматривать вариант "как я на ассемблере написал софтину, которая крутила фонарики и гимн спикером играла одновременно", то можно вспомнить и демосцену. Там все соки давили из системы, однако всё это и оставалось уделом горстки гиков, упражняющихся в затачивании алгоритмов под определенное железо. Да и товарищ не собирается переходить на данный уровень, как я понял. Он хочет AVR-JRE сделать, чтобы потом находится в комфортной среде.
9. Разработка многопоточного приложения де факто мало чем отличается от .. автоматного стиля для конечных автоматов. Там все ровно тоже самое: есть КА (поток), который получает данные извне (слушатель КА) и делает нечто, в общем-то наплевав на остальные КА в системе. Если требуется он может "сообщить" состоянием (семафором, послать сигнал потоку) другому КА, что тому следует сделать .. все ровно тоже самое.
Погодьте-ка чутка. Давайте представим примитивный "умный" примус с дисплеем, часами и датчиком давление по I2C. Клавиатурка на 1838. Датчик температуры 1W. Ну и, для понта, прилепим туда любой радиомодуль по SPI. Нахлабучим это всё на кол RTOS и что получим?
Давайте разберём транзакцию (к примеру) с дисплеем. 20*4=80 да плюс по 4 бита уже 160 и управляющие команды + старт-стопы. Округлим до 200 байт для простоты))) Вот мы открыли сессию по I2C, дисплей нам ответил и мы засылаем в него всю пачку данных за один раз (ардуинщики - это я про С+ или около!!!) и тут! вдруг мы не успеваем всё передать а управление передаётся другому потоку!
Так вот, как вы думаете, будет ли корректно работать такой код???
Только в сетевушку и видеокарту тоже все это пулять необходимо и с не меньшей скоростью ..
Правильно. Только не забываем про DMA и всё становится на свои места)))
6. Точно также как и свои функции. Открываете исходник и смотрите сколько там вложенных вызовов. Тут нет скомпилированных DLL модулей с закрытым кодом.
9. Вы просто ещё не разобрались в КА .. там все точно также банально ..
10 Рассинхронизм "атомарных" действий решается достаточно просто несколькими способами, от "отключить многозадачность для критического куска", до реорганизовать кусок убрав критичность. Тут как раз фигня написана про дисплей .. по нему (LCD1602) уже были баталии и было показано как примитивный драйвер I2C вполне нормально пуляет в него строки за 95микросекунд..
Погодьте-ка чутка. Давайте представим примитивный "умный" примус с дисплеем, часами и датчиком давление по I2C. Клавиатурка на 1838. Датчик температуры 1W. Ну и, для понта, прилепим туда любой радиомодуль по SPI. Нахлабучим это всё на кол RTOS и что получим?
Давайте разберём транзакцию (к примеру) с дисплеем. 20*4=80 да плюс по 4 бита уже 160 и управляющие команды + старт-стопы. Округлим до 200 байт для простоты))) Вот мы открыли сессию по I2C, дисплей нам ответил и мы засылаем в него всю пачку данных за один раз (ардуинщики - это я про С+ или около!!!) и тут! вдруг мы не успеваем всё передать а управление передаётся другому потоку!
Так вот, как вы думаете, будет ли корректно работать такой код???
На копеечном стм32ф0... с его ДМА и прерываниями - как два пальца... 12-15 задач не проблема... даже без РТОС...
Да, но речь то про AVR )))
Да, но речь то про AVR )))
А ссовцу пох, ему лишь бы дерьма на вентиллятор вкинуть.
Только в сетевушку и видеокарту тоже все это пулять необходимо и с не меньшей скоростью .. и на той же EGA особо не разбежишься, а 16 кадров в сек она пуляла даже на 286-м. А пищать Линукс так умеет и вовсе встроенным динамиком и изначально умел. В общем-то "параллельно". :)
Речь не о скорости а о наличии пауз в 1 мс или более.
Процессор пихнул себе по-быстрому в видеопамять или буфер видеокарты, а то и вовсе - настроил DMA и может несколько мс курить. Т.е. многозадачность в данном случае чисто аппаратная.
Я уже привел пример: попытайтесь только процессором сформировать видеосигнал с разрешением 1920х1280. Теоретически его производительности должно хватить, но пауза даже в 1 мкс, не говоря об 1 мс, сразу испортит всю картинку, а то и собъет синхронизацию.
Я уже Вам ответил: на 286 и EGA у меня драйвер вполне бегал 16 кадров в сек с разрешением 640х480 (другого там не было) катая на скоростях под 5 мегабайт в сек. в Ягушку.. да, было сильно хитрО закручено, ибо реализован был "псевдографический режим" а-ля спектрум .. и Вы путаете вывод в буфер драйвера и ФОРМИРОВАНИЕ ТВ-изображения НА ЭКРАНЕ (без памяти). Дергать развертку в нужных тактах - не есть задача НИКАКОГО даже микро- контроллера (для этого есть специально обученные схемы - счетчики, см. "Специалист" для просветления).
Давайте разберём транзакцию (к примеру) с дисплеем. 20*4=80 да плюс по 4 бита уже 160 и управляющие команды + старт-стопы. Округлим до 200 байт для простоты))) Вот мы открыли сессию по I2C, дисплей нам ответил и мы засылаем в него всю пачку данных за один раз (ардуинщики - это я про С+ или около!!!) и тут! вдруг мы не успеваем всё передать а управление передаётся другому потоку!
Так вот, как вы думаете, будет ли корректно работать такой код???
1. В ардуишной реализации буфер I2C - 32 байта. Первый - управляющий. Соответственно, все, что мы попытаемся запихнуть свыше 31 байта, будет потеряно.
2. Допустим мы работаем с союмтвенным софтовым I2C без всяких буферов, как говорится, по факту. Вы будете смеяться, но работать - будет. I2C - протокол с синхросигналом, где нормируются только минимальные длительности, максимальные могут быть какими угодно. Так что если мы прервем передачу по I2C на середине бита (даже не байта!), то по окончании прерывания протокол возобновит свою работу как ни в чем не бывало.
Так что пример - неудачный. А удачный пример я уже приводил - формирование полного телевизионного сигнала. И, кстати, передачу по Serial тоже прерывать нельзя ввиду отсутствия внешнего синхросигнала.
Я уже Вам ответил: на 286 и EGA у меня драйвер вполне бегал 16 кадров в сек...
Нифига Вы не ответили.
Вот если бы было "на 286 без видеоадаптера.." и далее по тексту - тогда другое дело.
И путаю не я, а Вы. Еще раз приведу ссылку, которую уже давал: https://code.google.com/archive/p/arduino-tvout/
Попытайтесь сделать то же самое на любой системе с многозадачностью. Ну и, естественно, видеоадаптер должен состоять из двух резисторов, безо всяких видеопамяти, генераторов строчной и кадровой и т.п.
2. Допустим мы работаем с союмтвенным софтовым I2C без всяких буферов, как говорится, по факту. Вы будете смеяться, но работать - будет. I2C - протокол с синхросигналом, где нормируются только минимальные длительности, максимальные могут быть какими угодно. Так что если мы прервем передачу по I2C на середине бита (даже не байта!), то по окончании прерывания протокол возобновит свою работу как ни в чем не бывало.
Так что пример - неудачный.
Возможно, я не притендую на очевидность. Но, если почитать мой "пример" ещё раз и вникнуть, зачем я "прилепил" на шину I2C аж целых ТРИ устройства, многое станет очевидным. Я прекрасно знаю как работает I2C шина и тд. и тп. НО... Допустим, мы прервали сессию связи с дисплеем по причине "невлезания" в квант времени, отданый RTOS потоку. И, допустим, следующий квант времени будет отдан опросу часиков. Поток СБРОСИТ шину и обратится УЖЕ к часикам!!! Повторный квант потока продолжит работу с дисплеем НО, до дисплея эти данные уже не дойдут! И будет наинтереснейший глюк, когда как вроде всё работает НО иногда глючит. Так шо... )))
Путаете Вы, и уже обьяснил почему. То что по ссылке некто приплел МК к задаче ни разу не требующей его .. так тут и как включить выключатель люстры ардуиной вопрошают .. не показатель ни разу. Маяться дурью можно по всякому. Не пример, ещё раз. И повторять тут нечего.
Насколько реально реализовать эти задачи в МП режиме,
Нет проблем. Кооперативная многопоточность делается в пол пинка, универсально, без извращений с автоматами и без ковыряния в железе: подключаете библиотеку coos для Ардуино, пишите свои независимые друг от друга потоки/задачи, они будут исполняться (квази)одновременно. Тысячу потоков не потянет (памяти и производительности не хватит), но 5-10 потоков - легко.
Кооперативная ось, помимо простоты, автоматически решает проблемы атомарности операций, выполняемых разными потоками. Об атомарности переменных, которые меняются в прерываниях, придется позаботиться, зато об остальном голова болеть не будет.
Можно и кооперативно, можно и вытесняюще, можно даже расширить типовой таймер millis() который будет исполнять задачи через timer_hook (тоже были образцы тут), можно прикрутить эту библиотеку, есть вариант на timer1 .. свой лисапед сварганить - вечерок посидеть, делов-то. Времени уйдет меньше чем потрачено на поломанные копья тут. :)
.. только это всё не для ТС-а.. хотя .. раз обещал показать - пусть делает. :)
.. только это всё не для ТС-а..
Ерунда, кооперативная ось как раз для него, все его "хотелки" выполняются. Он пока слегка "плавает", например, думает, что для каждой задачи/потока "нужен свой стек". Однако не нужен. Нужен небольшой клочок памяти для хранения контекста задачи, это все. В coos эта память отжирается, когда задается макс. число задач COOS_MAX_TASKS.
triac, вот допустим у вас работа разбирать и собирать планшеты или смарфоны и они потом работали. Можно ли заниматься разборкой и сборкой паралельно. Ну допустим надо выявить неисправность, заказать запчати и собрать. Легко если у вас несколько столов, легко если в процессе разборки вы укладываете запчасти в отведеную коробку. Но это проблематично если у вас привычка что в процессе разборки вы разбрасываете запчасти везде. Ну если с одним то куда ни шло. Но если вы их разбираете "многозадачно". Думаю проблема многозадачности у ТС возникла из-за неприятия менять себя и свои привычки. Ну как же он привык он это всегда делал. А собирала и приводила в порядок код тетя Джава. А здесь тети Джавы нет, все приходится ручками. Вот и спрашивает если у кого-то подобная тетя Джава на одолжить.
qwone, Ви не представляете какая у нас с сыном на рабочем столе "многозадачность" и, судя по вашей метафоре .. усё "на стеке" (как попало) .. зафотать? :)
Думаю проблема многозадачности у ТС возникла из-за неприятия менять себя и свои привычки. Ну как же он привык он это всегда делал. А собирала и приводила в порядок код тетя Джава. А здесь тети Джавы нет, все приходится ручками. Вот и спрашивает если у кого-то подобная тетя Джава на одолжить.
Для мелкоконтроллеров я пользуюсь кооперативными осями много-много лет. Лет пять назад в одном проекте подумал - дай-ка обойдусь по старинке, без оси, как все делают. Проект довел до конца, но очень ругал себя за такое решение, настолько это неудобно и, в сущности, глупо, если проект мало-мальски сложный. Вижу единственное оправдание, почему не использовать ось: незнание, что ее можно использовать.
Ну .. ежели "диспетчер задач" + типовой malloc() + небольшие макросы типа моего ovfGetCount(), ifMillis().. для упрощения работы с КА и событийной логикой, вкупе с парой недоклассов, называть "осью" .. то да. :)
Умеет сохранять/восстанавливать контекст - можно назвать осью, не умеет - называйте как угодно, "диспетчером задач", "прототредом" и т.д, и т.п.