fiber — легковесные процессы для Arduino


    А давайте притащим мир большого программирования в Arduino!


    Любая программа, а тем более программа близкая к аппаратуре (а какие еще на arduino бывают?) при рассмотрении представляет собой множество параллельно работающих ветвей.


    При этом в реальной жизни обработка большинства вещей в реальном времени не требуется. Достаточно иметь нечто похожее на реальное время.


    Например если мы программируем скажем гистерезисный регулятор температуры, то как правило совершенно не важно прямо сейчас сработает включатель нагревателя или через пару милисекунд.


    А вот если мы программируем скажем регулятор ШИМ (не рассматриваем аппаратные способы), то тут нам возможно потребуется считать каждый такт процессора, чтобы обеспечить приемлемую точность регулирования.


    Если рассмотреть структуру произвольного сложного программно-аппаратного проекта в том числе на Arduino, то увидим, что задач требующих "реального" (с жесткими требованиями) реалтайма — меньшинство, а большинству задач достаточно условного реалтайма.


    Программирование реального реалтайма — это как правило прерывания и аппаратные хитрости. В этой статье поговорим о программировании реалтайма условного.


    Давайте представим что мы разрабатываем скажем систему управления обычным бытовым холодильником. Эта система включает в себя:


    1. Регулятор температуры
    2. Органы управления этой самой температурой (пусть будет переключатель на три положения)
    3. Датчик открытия двери
    4. Свет в холодильнике
    5. Ну и например выход в интернет, куда ж без него.

    Управляем температурой


    Давайте попробуем рассмотреть для начала регулятор температуры. Как правило в холодильниках используют гистерезисное регулирование. Мы не будем придумывать велосипед и просто его реализуем.


    void
    temperature_regulator(void) {
    
        for (;;) {
            uint16_t current_t = get_adc(INPUT_T);
    
            if (current_t > t_on)
                enable_cooler();
    
            if (current_t < t_off)
                disable_cooler();
        }
    }
    

    Где: t_on и t_off — температуры гистерезиса. INPUT_T — вход АЦП измерения температуры. get_adc — некая функция производящая измерение АЦП. Функции enable_cooler и disable_cooler — соответственно включают и выключают охладитель.


    Вроде просто?


    Рассматривая поближе составляющие сразу натыкаемся на то, что многие вещи включают в себя циклы ожидания. Например функция get_adc могла бы выглядеть как-то так:


    uint16_t
    get_adc(uint8_t input)
    {
        while (adc_is_busy());
        adc_switch_mux(input);
        adc_start();
        while (adc_is_busy());
        return adc_value();
    }

    Где adc_switch_mux — переключает входной мультиплексор АЦП на нужный вход, adc_start запускает АЦП преобразование. Пока преобразование выполняется нам приходится ждать — пустой цикл пока adc_is_busy возвращает истину. Когда преобразование выполнится adc_value вернет нам результат.


    управляем светом


    Управление светом в холодильнике тривиально:


    void
    light_control(void)
    {
        for (;;) {
            if (sensor_door() == DOOR_OPEN)
                light_on();
            else
                light_off();
        }
    }

    О внедрении сюда выключения света по таймеру мы поговорим немного позднее. Сейчас попробуем соединить эти две программы.


    Обе программы вполне наглядны понять и написать их сможет школьник. Но как соединить их в один процесс?


    Самое простое — преобразовать программы в функции и вызывать их в бесконечном цикле. Именно этот подход предлагает нам Arduino с его традиционной функцией loop:


    void
    temperature_regulator(void) {
    
        uint16_t current_t = get_adc(INPUT_T);
    
        if (current_t > t_on)
            enable_cooler();
    
        if (current_t < t_off)
            disable_cooler();
    }
    
    void
    light_control(void)
    {
        if (sensor_door() == DOOR_OPEN)
            light_on();
        else
            light_off();
    }
    
    void
    loop(void)
    {
        temperature_regulator();
        light_control();
        ...
    }

    Вроде все просто? Но давайте вернемся к get_adc. Просто так уже эта функция не разворачивается. Можно конечно оставить все как есть (АЦП преобразование надолго нас не задержит), для случая холодильника возможно и подойдет, но давайте попробуем развернуть и этот цикл.


    Какие сложности возникают:


    1. Поскольку имеется возвращаемое значение get_adc, то нужно его где-то хранить
    2. Если АЦП не используется нигде в другом месте, то у разработчика возникает большой соблазн взять и сунуть измерение АЦП прямо внутрь temperature_regulator:

    enum adc_state { FREE, BUSY, VERYBUSY } state = VERYBUSY;
    
    void
    temperature_regulator(void)
    {
        uint16_t current_t;
        switch(state) {
            case VERYBUSY:      // АЦП не нами занято
                if (adc_is_busy())
                    return;
                state = FREE;
            case FREE:
                adc_switch_mux(input);
                adc_start();
                state = BUSY;
                return;
            case BUSY:
                if (adc_is_busy())
                    return;
                current_t = adc_value();
                state = FREE;
                break;
        }
    
        if (current_t > t_on)
            enable_cooler();
    
        if (current_t < t_off)
            disable_cooler();
    }

    Вроде не сильно сложно? Но из неприятностей:


    1. появилось внешнее по отношению к функции хранилище состояния АЦП-модуля
    2. мы смешали код работы с АЦП с кодом регулятора (инкапсуляция нарушена)

    Если мы АЦП захотим использовать еще в паре мест, то придется тщательно работать над рефакторингом:


    • восстанавливать инкапсуляцию (котлеты отдельно, мухи — отдельно)
    • организовать еще одно хранилище — результаты работы АЦП между вызовами надо где-то хранить

    Итого получается у нас при таком подходе недостатки:


    1. Резко возрастает сложность программ;
    2. Появляются внешние (по отношению к программным сущностям) хранилища данных (где мы их храним: в статических переменных или глобальных — вопрос стиля);
    3. Либо если мы хотим отказаться от внешних хранилищ данных, появляется протокол обмена данными (каждая функция может вернуть данные или признак их отсутствия. Другие функции будут обрабатывать данные или ничего не делать при их отсутствии.

    Если мы решим вывести наш холодильник в интернет, то программирование его в такой парадигме может стать адом.


    Как бороться с этим адом?


    Резкое занижение требований к ПО


    Это нормальный метод, если он подходит, то можно на нем остановиться. Помните выше мы сформулировали что можно не разворачивать функцию get_adc, а оставить как есть.


    И так сойдёт!


    Вполне себе работоспособный подход, для холодильника (без сложного интернета) подойдет вполне.


    На этом пути по мере наращивания сложности проекта обычно приходится наращивать аппаратную сложность, компенсируя ей сложность программную.


    Треды и процессы


    В какой-то момент возникает соблазн даже взять и портировать на нашу систему полноценные треды/процессы. Гугля находим массу проектов, например вот этот.


    Заглядывая в код треда видим все те же функции. Разглядывая код поближе — видим попытку организовать периодический вызов функций через примерно равные интервалы.


    Например


    loop() { ... }

    Вызывается максимально часто, а вот Thread.onRun можно сконфигурировать чтобы вызывался скажем раз в две секунды.


    То есть человек назвал тредом то что не является тредом в смысле CPU. Увы.


    Реальных тредов в том понимании как их понимают в "большом" мире я не нашел. Буду благодарен, если кто-то подбросит мне ссылку на такой проект.


    Однако в рамках обсуждения тредов и процессов скажу еще что в "большом" мире для решения задач треды обычно не применяют.
    Почему? Реализация тредов (процессов) неизбежно приводит нас к введению понятия "квант времени": каждый тред/процесс выполняется определенный квант времени, после чего управление у него отнимается и передается другому треду/процессу.


    Такая многозадачность называется вытесняющей: текущий процесс вытесняется следующим.


    Почему в рамках "больших" проектов треды в основном не применяются? Для того чтобы заставить работать множество тредов на одном CPU необходимо делать очень маленький квант времени. Частота квантования например на современном Linux — равна 1000Гц. То есть если у Вас в системе выполняется 1000 процессов одновременно, то каждый из них будет получать 1 квант времени на 1мс один раз в секунду (это если оверхеда на вытеснение нет), а в реальном мире переключая 1000 процессов хорошо если получится выдать каждому по милисекунде раз в десять секунд.


    Кроме того, поскольку многозадачность вытесняющая, то возникает масса вопросов по межпроцессному взаимодействию. Возились с гонками между прерыванием Arduino и основной программой? И здесь те же проблемы.


    В общем все нагруженные, так называемые HighLoad проекты в "большом" мире делают без массового использования тредов. Проекты HighLoad делают с применением кооперативной, а не вытесняющей многозадачности.


    Чтобы обслужить 1000 клиентов выделив каждому тред — нужно примерно 20 современных компьютеров. При том что на практике достаточно одного сервера чтобы обслужить 50 тыс клиентов.


    Кооперативная многозадачность


    Что это такое? Вот типовой loop() проекта Arduino и есть один из вариантов кооперативной многозадачности: переключение к следующей функции не произойдет до тех пор пока предыдущая не завершится. Все функции стараемся писать чтобы они возвращали управление максимально быстро и таким способом решаем задачу.


    Этот способ реализации кооперативной многозадачности можно называть колбечным (или функциональным).
    Если обратиться к "большому" миру, там есть проекты для HighLoad построенные исключительно на этом способе, например тот же Node.JS.


    Если Вы почитаете отзывы о Node.JS, то увидите весь набор от восторженных "наконец я нашел инструмент на котором МОЖНО реализовать мою задачу", до типовых: "callback hell!".


    Существует второй способ реализации кооперативной многозадачности — сопрограммы (корутины, файберы). Идея тут примерно такая же как в традиционных тредах: каждый процесс работает как бы независимо от других. Однако ключевое отличие тут в том, что переключение между процессами производится не по таймеру, а тогда, когда сам процесс решит что ему процессор больше не нужен.


    Какие прелести дает подобный подход?


    1. Нет ада функций;
    2. Межпроцессное взаимодействие очень простое (ведь если процесс не прервут в критической секции, то и само понятие "критическая секция" нивелируется): мютексы, семафоры — все или резко упрощается или заменяется простыми переменными;

    "Лучшие умы человечества" (ц) разрабатывавшие в прошлом веке для нас язык C и писавшие о нем книги по которым многие из нас учились читать, попытались обобщить все достоинства и тредов и кооперативной нефункциональной многозадачности и в итоге родился язык для HighLoad — Go.


    Но впрочем давайте вернемся из большого мира в наш мир Arduino. Go у нас нет, поэтому будем работать с тем что есть.


    Кооперативная многозадачность в Arduino


    Итак нам нужны:


    1. Возможность создать процесс;
    2. Возможность переключиться на другой процесс из процесса.

    Традиционное название функции переключения между процессами — yield или cede.


    Вернемся к нашей функции get_adc:


    uint16_t
    get_adc(uint8_t input)
    {
        while (adc_is_busy());
        adc_switch_mux(input);
        adc_start();
        while (adc_is_busy());
        return adc_value();
    }

    Если бы у нас были кооперативные процессы, то в их среде ее бы следовало доработать до следующего вида:


    uint16_t
    get_adc(uint8_t input)
    {
        while (adc_is_busy())
            cede();         // пока ждем - пусть другие работают
        adc_switch_mux(input);
        adc_start();
        while (adc_is_busy())
            cede();         // пока ждем - пусть другие работают
        return adc_value();
    }

    Температурный регулятор выглядел бы так:


    void
    temperature_regulator(void) {
    
        for (;;) {
            uint16_t current_t = get_adc(INPUT_T);
    
            if (current_t > t_on)
                enable_cooler();
    
            if (current_t < t_off)
                disable_cooler();
        }
    }
    

    Но позвольте! Тут же никаких изменений нет! Скажете Вы. А все изменения вошли в get_adc, зачем нам еще?


    Ну и управление светом тоже доработаем:


    void
    light_control(void)
    {
        for (;;) {
            if (sensor_door() == DOOR_OPEN)
                light_on();
            else
                light_off();
    
            cede(); // сам поработал - дай другому
        }
    }

    Красиво? Наглядно? По моему максимально наглядно насколько это возможно.


    Все используемые нами функции подразделяются на два вида:


    1. вызывающие yield/cede внутри себя
    2. остальные

    Если в Вашем цикле есть хоть одна функция гарантировано вызывающая yield/cede внутри себя, то добавлять вызовы cede()/yield() не нужно.


    В "большом" мире хорошим тоном считается писать вызовы cede()/yield() внутри так называемых низкоуровневых функций и сводить вызовы этих операторов к минимуму.


    Сколько это будет стоить?


    Поскольку процессы все-таки слабо зависимы друг с другом (хоть и передают друг другу управление), то, очевидно, у каждого процесса должен быть собственный стек.


    Собственный стек — понятие относительно дорогое. Происходит например прерывание. В стек попадает текущий адрес выполнения программы. Так же в стек попадают все регистры которые будут использованы в прерывании.
    Вы вызываете функцию: в стек попадают адрес возврата, все ее аргументы и ее временные переменные.


    Я занимался замерами, практика показывает что прерывание обслуживающее например таймер (проинкрементировать счетчик, послать уведомление) занимает на стеке 16-30 байт. Ну и обычный цикл тоже доходит до 16-30 байт глубины. Например наш temperature_regulator занимает на стеке:


    1. всего 2 байта под свою переменную
    2. 2 байта на вызов get_adc
    3. 1 байт на аргумент для get_adc
    4. 2 байта на вызов adc_switch_mux
    5. 1 байт на ее аргумент

    Итого 2 + 2 + 1 + 2 + 1 = 8 байт. Плюс компилятор посохраняет регистры в стек/подостает их оттуда. Умножим на два. Плюс возможный вектор прерывания. Итого получается где-то 50-60 байт на файбер нам было бы достаточно. Сколько файберов можем запустить на Arduino nano328? 5-10 штук со стеком 64-128 и еще останется память для всего остального.


    Расходы памяти на 5-10 полноценных файберов стоят упрощения реализации алгоритмов программы? Ну и поскольку 640 килобайт хватит всем 5-10 файберов хватит для того чтобы комфортно написать не только холодильник но и скажем http-клиента займемся написанием такой библиотеки!


    Прототип


    Мной реализован прототип (уже можно пользоваться но API будет расширяться) библиотеки файберов для Arduino. Пока только AVR (есть завязки на avr-libc).


    Данная статья пишется в гит того же проекта и оригинал ее (будет дорабатываться) лежит здесь.


    Библиотека написана на чистом C (не C++).


    API


    Начинается все с инклюда и инициализации:


    #include <fiber.h>
    
    void
    setup()
    {
        ...
        fibers_init();
    }

    Для создания файбера используется функция fiber_create, принимающая ссылку на заранее выделенный для него стек, его размер и ссылку на данные которые будут переданы в файбер:


    struct fiber *
    fiber_create(fiber_cb cb, void *stack, size_t stack_size, void *data);

    Для того чтобы не мучиться в программе над выделением стека, предусмотрены пара макросов:


    FIBER_CREATE(__cb, __stack_size, __data);
    FIBERV_CREATE(__cb, __stack_size);

    Которые за Вас выделят память в статической области (обратите внимание: malloc не используется, поэтому нельзя применять эти макросы в цикле).


    Или даже если Вы определите заранее какой размер стека будут иметь все Ваши файберы то два макроса:


    FIBER(__cb, __data);
    FIBERV(__cb);
    

    для определения файбера.


    Файбер может иметь несколько состояний, вот базовые:


    • 'работает' — обычное состояние
    • 'усыплен' — не автопланируется

    Усыпить можно только текущий файбер (то есть сам файбер себя усыпляет, получив ссылку на себя fiber_current) вызвав функцию fiber_schedule, разбудить — функцией fiber_wakeup:


    
        struct fiber *waiter;
    
        // где-то в файбере
        waiter = fiber_current();
        fiber_schedule();
    
        // где-то в другом месте, например в прерывании или другом файбере
        if (waiter) {
            fiber_wakeup(waiter);
            waiter = NULL;
        }

    На механизме усыпления/пробуждения можно сокращать использование CPU на циклах ожидания: если Ваш файбер сейчас ждет и есть кому разбудить (например прерывание), то можно его усыпить: другие файберы получат больше процессорного времени на работу.


    Передача управления из процесса в процесс выполняется вызовом fiber_cede():


    void
    light_control(void)
    {
        for (;;) {
            if (sensor_door() == DOOR_OPEN)
                light_on();
            else
                light_off();
    
            fiber_cede(); // сам поработал - дай другому
        }
    }

    Тонкости


    • Никакие функции (кроме fiber_wakeup) нельзя вызывать из прерываний. Это обстоятельство видимо не преодолеть;
    • Нет возможности контроллировать автоматически переполнение стека;

    Соответственно некоторые файберные паттерны из "большого" мира тут применять не получится. Данная библиотека годится под паттерн: на стадии инициализации запускаем N файберов и дальше они работают.


    Паттерн "при событии запускаем файбер", при повторном — еще один — тут увы не проходит. Ресурсов Arduino не хватит. Но можете "разбудить" того кто обрабатывает редкие события.


    Паттерн: положи ссылку на себя в переменную, засни, а прерывание тебя разбудит — имеет тонкости: прерывание может прийти раньше чем мы заснём. На эту тему решение внедрено, но требует дополнительного разъяснения. Просто исходите из того что так делать МОЖНО.


    Что не доделано


    1. Пока не дооформил как библиотеку Arduino: не смог понять пока как заставить его компилировать (из GUI имеется ввиду, с Makefile-то все просто) C'шные файлы в стандарте C99 (даже заголовки avr-libc предполагают C99). Не хочу оформлять как C++ (потому что не только Arduino в планах);
    2. В большом мире есть fiber_join, так и не знаю стоит ли его реализовывать.
    3. Больной вопрос: если программа использует регистровые переменные и при этом переключает файберы, то предсказать поведение невозможно. Сохранять ВСЕ регистры на стеке — дополнительный оверхед. Пока не натыкался на эти проблемы. Возможно придется сделать опцию: будут файберы более требовательны к памяти, но более надёжные;

    В общем буду рад коментариям, дельным предложениям и pull-реквестам :)


    Пинг-понг на файберах:


    #define FIBER_STACK_SIZE 64
    #include <fiber.h>
    #include <stdio.h>
    
    void
    ping(void *data)
    {
           printf("ping\n");
           fiber_cede();
    }
    
    void
    pong(void *data)
    {
         printf("pong\n");
         fiber_cede();
    }
    
    void
    setup(void)
    {
           fibers_init();
           FIBERV(ping);
           FIBERV(pong);
    }
    
    void
    loop()
    {
         fiber_schedule(); // этот файбер нам не нужен
    }

    Ссылки


    1. Библиотека fiber;
    2. Эта статья в Git;
    3. Библиотека Thread, в тексте статьи;
    4. Многозадачность в терминах википедии;
    5. Когда-то на HighLoad выступал о аналогичном но в "большом" мире;
    6. Node.JS.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 125
    • 0

      Разработка интересная, но…
      Сомнительный посыл про то, что вытесняющая многозадачность не подходит. Сейчас у меня в системе ~2156 потоков. Каких-то проблем, которые должны возникнуть, если каждый поток выполняется 1мс за 10-20с не обнаруживается. Ответ заключается в приоритетах и ожиданиях.


      На встраиваемой системе потоков обычно не много. И чаще всего им не надо работать постоянно. Большая часть потоков находится в состоянии блокировки и ожидании событий, планировщик их не вызывает. А ОСРВ с вытесняющей многозадачностью удобнее и проще в использовании зачастую (кроме общего доступа). Тот же FreeRTOS легковесен и доступен под AVR.

      • 0

        Проблема вытесняющей многозадачности — в повышенном (в разы, по сравнению с кооперативкой) требовании к оперативной памяти. Каждая задача требует как минимум места под полный контекст процессора и отдельно еще (в лучшем случае) стек под прерывания.


        1. На некоторых МК недостаточно ОЗУ, чтобы на каждый чих выделять стек (особенно когда трудно предсказать его загруженность)
        2. Не считая FreeRTOS (у меня к ним претензии только за naming convention), многие RTOS не распространены дальше одной-двух платформ. Кооперативки в чистом виде (Protothreads) работают на любом компиляторе.

        Но мне нравится идея вытесняющей многозадачности, а еще больше нравится концепт QP, жаль для коммерческого использования оно платное, а просто так поиграться еще времени не появлялось

        • +1
          Тот же FreeRTOS легковесен и доступен под AVR.

          надо посмотреть на него, спасибо

          • 0
            Ответ заключается в приоритетах и ожиданиях.

            Я правильно понимаю, что при таймере с частотой 1000 Гц потоку гарантируется максимум в 1 мс времени каждую секунду, но если он в состоянии S, то переключение, фактически, произойдёт намного быстрее, и неиспользованное время достанется другим потокам, выполняющим код? Ну это при условии, что у всех потоков равный приоритет, конечно. А при неравных кто-то, у кого приоритет выше, может получить заведомо больше одного тика?


            Вообще, я думал, таймер и квант выполнения не связаны и отличаются на порядки. Например, в Debian ядро собирают с таймером 100 Гц, неужели там настолько крупные кванты, по 10 мс?

            • 0

              Да. Например, если поток пытался взять мьютекс и уснул, то система не будет давать ему процессорное время, до тех пор, пока мьютекс не будет освобожден (правда, для коротких пауз есть спинлоки, чтобы не иметь лишних затрат на смену контекста). Будут вызываться другие потоки.


              неужели там настолько крупные кванты, по 10 мс?

              Не нашел информации, но может быть. Debian же часто применяется как серверный дистрибутив, у них часто квант больше.

              • +1

                Попытаюсь объяснить, так как это является одной из основных функций типовых операционных систем реального времени.
                В ОСРВ задачей таймера с частотой 1000Гц — это просто делать прерывание каждую миллисекунду, которое вызывает одну конкретную функцию ОС — планировщик задач. При этом приоритет этого таймера выше приоритета всех выполняющихся задач в системе, чтобы планировщик гарантированно выполнялся раз в миллисекунду.
                Что же делает планировщик задач? В зависимости от выбранного типа многозадачности он может:


                • При round-robin многозадачности, он проверяет израсходовала ли текущая задача свой лимит времени (это обычно в несколько раз выше частоты планировщика. При 1мс, это может быть 4-10мс) и если да, переключает контекст на следующую задачу с таким же приоритетом, если она готова к выполнению.
                • При вытесняющей многозадачности планировщик смотрит нет ли более высоко-приоритетной задачи, которая готова к выполнению и переключается на нее, если такая есть.
                • Иначе продолжает выполнение текущей задачи.

                Таким образом при round-robin задаче гарантируется определенное непрерывное время исполнения, которое можно настроить. При preemptive время гарантируется только самому высоко-приоритетному потоку, и для правильной работы надо распределять приоритеты между задачами, например по концепции rate-monotonic scheduling.


                Благодаря этому в ОСРВ реализуется основное понятие реального времени — гарантированное время реакции, которое в данном конкретном случае будет составлять 1мс.

                • 0

                  О, спасибо, вот эту информацию я как-то и не мог найти. В частности, чем же отличается preemptive kernel от обычного, вроде, везде уже в современных ОС многозадачность не кооперативная. А preemptive я лично собираю, потому что без него в PulseAudio появляются ощутимые скипы, теперь понятно, откуда это всё. Хотя линукс без патчей и не является ОСРВ, эти концепции подходят.

                  • 0

                    Вообще-то переключение контекста может произойти и гораздо раньше одной миллисекунды, если просемафорил не таймер, а какое-то другое прерывание. Если задача, ждущая семафор, находится выше по приоритету, чем активная, то после выхода из прерывания произойдет переход в задачу с семафором.

                    • 0

                      Ну да, но это уже более детально.
                      В частности, естественно, переключение контекста также произойдет раньше, если текущая задача заблокировалась, например в ожидании какого либо флага, или ей надо сделать паузу. Тогда произойдет автоматическое переключение на следующую готовую задачу такого же приоритета или на продолжение выполнения более низкоприоритетной задачи, которая до этого была прервана планировщиком

                    • 0
                      1. При round-robin многозадачности...
                      2. При вытесняющей многозадачности планировщик ...

                      round-robin scheduling в вашем описании — тоже вытесняющая многозадачность. Если все задачи во втором случае имеют одинаковый приоритет — получается как-раз round-robin scheduling, просто есть и другие алгоритмы планирования. Противоположность вытесняющей многозадачности — кооперативная. Т.е. важно кто инициирует переключение контекста: если планировщик по таймеру или еще как, то вытесняющая, а если сама задача «уступает» — то кооперативная. Как-то так. А в остальном — согласен на все сто.
                  • 0
                    > Сейчас у меня в системе ~2156 потоков.
                    > Ответ заключается в приоритетах и ожиданиях.

                    у Вас в системе 2000 потоков, но и событий в секунду крайне немного. Если пустить хотя-бы 100 событий в секунду будящих случайные из 2000 потоков, то система будет работать где-то на грани около максимума производительности.

                    если поток событий возрастет до 500 в секунду — то потоковая модель уже просто будет стоять и требовать апгрейда.
                    меж тем ОДИН поток на асинхронной парадигме вполне справится с 15 тыс событий в сек.

                    обслуживать запросы 50К клиентов одним CPU — вполне рядовая задачка. и 50К ограничивается как правило не CPU а числом сокетов :-\
                    • 0

                      Так я это и привелтв ккчестве примера того, что большинство потоков спят.

                      • 0

                        я это понимаю. я писал что в современных HighLoad модель обслуживания запросов клиентов тредами как правило не применяют.


                        фиксированный пул тредов — да, по треду на клиента — редкость.


                        у Вас получилось иметь приемлемую нагрузку при 2000 процессах, но среднестатистически это не получается. У меня одно объяснение — у Вас низкая частота событий в системе — можете себе позволить "спать" всем этим 2000.


                        но это как бы не хайлоад. все эти 2000 тредов можно заменить на 2000 файберов в одном процессе и у системы появится возможность нарастить число клиентов на том же одном процессе до 20000 :)


                        как-то так :)

                        • 0

                          Ну я и не спорю. Более того, часто схема запрос каждого пользователя обрабатывается быстро и подключение не висит долго. Потоковая модель потребовала бы создание нового треда, а затем завершение, что еше более накладно.


                          но это как бы не хайлоад. все эти 2000 тредов можно заменить на 2000 файберов в одном процессе и у системы появится возможность нарастить число клиентов на том же одном процессе до 20000 :)

                          Я привел в пример просто свой десктоп с win10. Ясно, что тут своя специфика. Много разнородных поэроцессов и потоков

                          • +1
                            > Я привел в пример просто свой десктоп с win10

                            а десктоп. десктоп — это такая штука которая 99.9% времени ничего ж не делает (ждет ввода пользователя).
                  • +1

                    А как насчёт FreeRTOS http://www.freertos.org? Вроде бы все что нужно есть — таски (они же треды), и очереди для коммуникации между ними в стиле go.

                    • +1
                      Для кооперативной многозадачности в AVR'ах, пока ничего лучше Protothreads не придумали. Есть и порт на C++.
                      • 0

                        прототред — это по сути работа над калбечным вариантом кооперативной многозадачности.


                        то есть все тот же loop по сути, который препроцессором преобразуется в некое подобие функций.
                        программирование ПОХОЖЕ на традиционное, но использование переменных на стеке затруднено (поскольку функция все равно перевызывается, то переменные в ней между вызовами не живут).


                        в данном же случае мы пишем приложения в обычном стиле

                        • 0
                          использование переменных на стеке затруднено

                          Верно, но это касается лишь функций которые содержат вызовы wait/yield, а в них все равно требуется повышенная внимательность при написании. Кроме того, сохранение пары переменных состояния, обычно гораздо дешевле сохранения всего контекста. А с учетом возможностей нынешних компиляторов по оптимизации кода без указателей на функции, такие переменные вообще могут не занимать места в статической памяти.
                      • 0
                        Есть очень мелкая оська для всяких микрашей под названием OSA. Минимальна, работает даже на тиньках.
                        • +4

                          Боже, какой замечательный велосипед! И как хорошо, что такие "большие" программисты еще не добрались до автопилотов и систем управления автомобилей, а то было бы совсем худо.
                          Вы еще даже не выбрались в интернет со своим холодильником и не поуправляли ничем сложнее, чем GPIO и ADC, а уже изобрели подобие RTOS, понятие какого-то условного реалтайма, попытались представить себе тысячную многозадачность на микроконтроллере…
                          Данный пост — это очень интересный пример, как Ардуино извращает понимание проектирования встраиваемых систем до неузнаваемости.


                          Мой первый совет. Выкиньте все, что вы написали и почитайте хоть пару книжек про встраиваемые системы. Прикиньте, например, как сделан контроллер для стиральной машины. Посмотрите на реализацию систем программирования ПЛК МЭК 61131-3 — они как раз используются для управления в реальном времени и прерываний там нет.

                          • +1
                            Боже, какой замечательный велосипед! И как хорошо, что такие "большие" программисты еще не добрались до автопилотов и систем управления автомобилей, а то было бы совсем худо.

                            а что ж хорошие программисты, которые программируют автопилоты не могут нам ничего на старт предложить в Arduino, кроме Blink.ino delay которого базируется на пустых циклах?


                            Вы еще даже не выбрались в интернет со своим холодильником и не поуправляли ничем сложнее, чем GPIO и ADC, а уже изобрели подобие RTOS

                            10 лет назад я ушел из Embedded, сейчас вернулся на ардуино для "домашней" (то есть в личных целях) задачки и пытаюсь полученный в области "большого" мира опыт перенести туда над чем я мучился еще 10 лет назад.


                            последний проект 10 лет назад как раз был построен на калбеках


                            вот кусочек кода из последнего проекта (типа плата о себе раз в пол секунды в CAN-шину чет передает):


                            // общий init
                            ...
                            event_timer(DELAY_s(.2), _send_status);
                            ....
                            static void _send_status(struct timer *tmr) {
                                static uint8_t stage;
                                struct can_message msg;
                            
                                led_switch(STATUS_SEND_LED);
                                uint8_t sensor;
                            
                                switch(stage) {
                                    /* когда все передано, начинаем с начала */
                                    default:
                                        stage = 0;
                            
                                    case 0:
                                        msg.id = CAN_MEASURE_T1;
                                        sensor = T1;
                                        break;
                                    case 1:
                                        msg.id = CAN_MEASURE_T2;
                                        sensor = T2;
                                        break;
                            ...
                            stage++;
                            msg.sample.value = sensor_value(sensor);
                            can_send_message(&msg);
                            ....

                            то есть еще 10 лет назад возявкались мы с этими же колбеками которые предлагаются ардуиной сейчас. Мало того тогда все эти обвязки вроде event_timer писали сразу для AVR/ARM/PIC переносимо.
                            Всякие CAN/ModBus прокси и прочее — на калбеках — это АД. Пусть и структурированный.


                            Сейчас мне потребовалось реально "холодильник в интернет вывести" и я как посмотрел на тот ад что предстоит: весь этот набор команд AT — стейтмашину хоть бери да на рагеле пиши. И кстати почему бы и не на рагеле/флексе ее и не написать?


                            Вы, настоящий embedded программист, как относитесь к идее общение с WiFi на рагеле/флексе написать?

                            • –1
                              а что ж хорошие программисты, которые программируют автопилоты не могут нам ничего на старт предложить в Arduino, кроме Blink.ino delay которого базируется на пустых циклах?

                              Почему не могут? Вы же не спрашиваете. :-)


                              то есть еще 10 лет назад возявкались мы с этими же колбеками которые предлагаются ардуиной сейчас.

                              Ну как бы у меня тоже 15 лет опыта и с калбеками я не возявкался, хотя на одном 8-битнике и RS232 и CAN и таймеры с SPI — и все работало в реальном времени. Так что не могу сказать, что "Мы". Скорей "Вы", это не было мейнстримом.


                              Вы, настоящий embedded программист, как относитесь к идее общение с WiFi на рагеле/флексе написать?

                              Никак. Я не знаю что такое "на рагеле/флексе".

                              • +2
                                > Ну как бы у меня тоже 15 лет опыта и с калбеками я не возявкался

                                а с чем возявкались? если не калбеки то что? вариантов то немного же

                                > Никак. Я не знаю что такое «на рагеле/флексе».

                                языки программирования предназначенные для работы со стейтмашинами
                                • 0
                                  Так что не могу сказать, что "Мы". Скорей "Вы", это не было мейнстримом.

                                  так расскажите в двух словах, как мейнстрим программит параллельные процессы-то?

                                  • +4

                                    Если говорить о серьезном ембеддерском мейнстриме — который идет сегодня в реальное железо — авто/мото/самолето/ракето-электронику, индустриалку, и прочую электронику, которая хоть чем-то управляет в реальном времени, то в первую очередь это ОСРВ.
                                    µC/OS, RTX, QNX, vxWorks, FreeRTOS и куча других ОС, которые портированы на сотни встраиваемых аппаратных платформ(Arduino, кстати часто в их числе) и дают реальную многозадачность из коробки на любой вкус и кошелек.

                                    • 0
                                      можете привести пример приложения, которому требуются ДВА процесса реального времени не реализуемые на прерываниях и заодно поведать о том какое время гарантированной реакции процесса дает FreeRTOS например?
                                      • +2

                                        Не очень понятно, что вы хотите. Почему именно два, а не пять или десять? Причем здесь прерывания? Про время гарантированной реакции я, по-моему, понятно объяснил вот здесь. FreeRTOS, насколько я знаю, также исповедует данный общий принцип

                                        • 0
                                          ну хотя бы два. я просто, как вы понимаете, не такой специалист и представить себе некоторых вещей не могу ;)

                                          итак РЕАЛЬНОЕ применение с двумя процессами которым требуется реалтайм есть?
                                          • 0
                                            итак РЕАЛЬНОЕ применение с двумя процессами которым требуется реалтайм есть?

                                            Ну вот у вас же самих реальное применение:


                                            • Управлять лампочкой по датчику
                                            • отслеживать температуру в холодильнике.
                                              Два независимых процесса.

                                            Также при rate-monotonic scheduling каждое время цикла должно исполняться в отдельном процессе.

                                            • 0
                                              Два независимых процесса.

                                              независимых != реалтаймовых.


                                              я же в статье и пишу про то что вытесняющая многозадачность практически нигде не нужна.
                                              но Вы тут спозиционировали себя как специалиста который не велосипедит а знает как правильно.


                                              Так что не могу сказать, что "Мы". Скорей "Вы", это не было мейнстримом.

                                              вот я и интересуюсь, что там в мейнстриме? есть ли примеры РЕАЛЬНЫЕ? для расширения кругозора так сказать

                                              • +1
                                                независимых != реалтаймовых.

                                                Почему Вы считаете, что у вас не-реалтаймовые процессы? Думаете, что если у вас лампочка зажжется на пару секунд позже, это не будет Вас раздражать?


                                                я же в статье и пишу про то что вытесняющая многозадачность практически нигде не нужна.

                                                Еще один пример независимых процессов — это обработка клавиатуры/кнопок и отображение. Поэтому практически в каждом устройстве вокруг вас, которое имеет дисплей, кнопки и чем-то управляет — стиральная, кофейная машина, лифт, — у вас будут разные процессы, где обработка клавиатуры будет иметь свой приоритет. И если в каком-то из таких устройств кнопки будут "тормозить" — то скорей всего RTOS там нет.

                                                • 0
                                                  Думаете, что если у вас лампочка зажжется на пару секунд позже, это не будет Вас раздражать?

                                                  Пара секунд — будет
                                                  пара милисекунд нет


                                                  а второе делается без всякого реалтайма


                                                  Еще один пример независимых процессов — это обработка клавиатуры/кнопок и отображение.

                                                  обработка кнопок опять реалтайм не нужен.


                                                  пользователь нажмет кнопку: свет зажжется сразу по нажатии или через 20 милисекунд — совершенно безразлично.


                                                  то есть обработка кнопок — опять задача не реального времени.
                                                  параллельных процессов — да. Но зачем параллельные реалтаймовые процессы тут?

                                                  • +3

                                                    Потому, что вы упорно в своих рассуждениях не хотите заметить одну вещь:


                                                    Думаете, что если у вас лампочка зажжется на пару секунд позже, это не будет Вас раздражать? Пара секунд — будет

                                                    Это фейл.


                                                    обработка кнопок опять реалтайм не нужен.
                                                    пользователь нажмет кнопку: свет зажжется сразу по нажатии или через 20 милисекунд — совершенно безразлично.

                                                    А если через 40 мс- это фейл.


                                                    То есть обе задачи у вас — это задачи реального времени. Вам нужно, чтобы система среагировала за определенное время, и если она этого не сделает — все, суши весла — функция уже никому не нужна. Разница между этими задачами только в допустимом максимальном времени реакции. В одном случае оно порядка десятых долей секунды, в другом — десятки миллисекунд.


                                                    И вот это максимальное время реакции — оно фиксировано. Его не изменишь в проекте потом, его не поменяешь в требованиях. Во многих вещах оно вообще ограничено физическими законами — например в системах защиты электросетей защитным устройствам надо среагировать за пол-периода частоты сети — это 10мс. Поэтому это время вам придется соблюдать, независимо от количества задач в вашем контроллере и его загрузки и на любой стадии проекта.


                                                    Вам просто кажется, — ой ну пусть свет в холодильнике будет зажигаться максимум, скажем, через 0,3 секунды, а задержка обработок кнопок будет максимум 40мс.
                                                    С двумя этими задачами вы справитесь и с прерываниями. И вроде как свободного времени у процессора осталось полно. Но потом добавите свой Wi-Fi модуль, АЦП, AT-команды, SD-карту и — ой — худшее время реакции на клавиатуру вдруг стало не 40, а 100мс. И что будете делать? Начнете говорить, что 40 и 100мс — это тоже безразлично? Рассказывать про какой-то условный реалтайм?

                                                    • –1
                                                      > А если через 40 мс- это фейл.

                                                      и 40 мс — не фейл. 0.04 секунды пользователю пофиг
                                                      400 мс — да фейл.

                                                      > То есть обе задачи у вас — это задачи реального времени.

                                                      что такое ОС реального времени и почему там разговоры ведут о методах вытеснения процессов? потому что разговор всегда ведется не о 40-400 милисекунд, а о 40-1000 микросекунд

                                                      то есть таки понятие «реальное время» это о микросекундах.

                                                      если говорить о милисекундах — какая разница: ROUND ROBIN, PREEMPTIVE или вообще кооп многозадачность?
                                                      никакой разницы.

                                                      с реакцией 60 милисекунд можно даже по USART отвечать вполне: никого эта пауза не взволнует особо
                                                    • +1
                                                      Думаете, что если у вас лампочка зажжется на пару секунд позже, это не будет Вас раздражать?

                                                      Пара секунд — будет
                                                      пара милисекунд нет

                                                      а второе делается без всякого реалтайма


                                                      Так если у вас в системе гарантируется определённая задержка между сигналом с датчика и включением лампочки — пара миллисекунд — то это и есть реальное время. С учётом того, что от нарушения гарантий ничего особо страшного не произойдёт — это мягкое реальное время.

                                                      Еще один пример независимых процессов — это обработка клавиатуры/кнопок и отображение.

                                                      обработка кнопок опять реалтайм не нужен.

                                                      пользователь нажмет кнопку: свет зажжется сразу по нажатии или через 20 милисекунд — совершенно безразлично.


                                                      Боюсь, что нет — если пользователь, вызубрив все функции устройства, начнёт управлять им тыкая по кнопкам заученными движениями, а устройство будет тупить, потому что у нас нет гарантированного времени реакции на действия пользователя, то ничего кроме ненависти к разработчику такое устройство не принесёт.
                                                      • 0
                                                        Так если у вас в системе гарантируется определённая задержка между сигналом с датчика и включением лампочки — пара миллисекунд — то это и есть реальное время.

                                                        я никогда не буду заниматься обеспечением гарантии этого времени для лампочки.


                                                        именно поэтому я просил Вас привести реальный пример мест где это нужно. Причем чтобы это нужно было в количестве 2+ штук на устройство.


                                                        вот мы например делали векторное управление двигателем: там жестко было: надо было дифуравнение порешать 6 раз за электрический оборот: там никакая RTOS не подходила: дифура решалась тупо в прерывании (и плевать что занимала 9/10 процессорного времени), а оставшееся от основной реалтайм-функции время распределялось машиной условных таймеров (дает в среднем X вызовов функции в секунду) между всеми остальными задачами.


                                                        приложений где надо было ДВЕ задачи реального времени решать — я не встречал (прерывания не считаются задачей реального времени: то есть считаются, но это решение аппаратное, а не операционной системы реального времени)

                                                        • +2

                                                          Простой пример — система управления лифтом:


                                                          • цикл управления движением кабины и открытия закрытия дверей — порядка 5мс, так как иначе лифт не будет успевать отрабатывать показания датчиков и неточно останавливаться (на скорости 4м/с за 5мс лифт проезжает 20см). Также нужна защита привода от перегрузок, которая должна отрабатываться через четко определенное время.
                                                          • опрос кнопок вызова на этажах и кабине — раз в 20мс. Быстрее не надо и иначе надо отрабатывать дребезг. Медленнее — люди начнут бить по кнопкам.
                                                          • алгоритм, который определяет какому лифту на какой этаж ехать — 200мс. Быстрее не получится, так как там нечеткая логика, медленней — не будет поспевать за изменяющейся ситуацией.
                                                          • параллельно всему этому идет обмен по Modbus RTU, CAN и RS232.
                                                          • параллельно этому всему опрос и обновление порядка сотни различных логических сигналов. Защита от нештатных ситуаций (неправильные комбинации, обрыв цепей )
                                                          • –1
                                                            вот в этом списке критическое только обработка концевиков связанных со скоростью лифта. Тут эта хрень скорее всего реализуется на прерывании.
                                                            Но даже в рамках указанных допусков — милисекунда — это сколько тысяч инструкций AVR? Нафига тут вытеснение?

                                                            типа мы неправильно построили архитектуру: вывод который должен генерить прерывания — не генерит и мы исправляем это RTOS'ом с вытеснением?
                                                            жуть какая-то

                                                            > алгоритм, который определяет какому лифту на какой этаж ехать — 200мс. Быстрее не получится, так как там нечеткая логика

                                                            эта, ну пусть 100 этажей. что ж за алгоритм там? задачу комивояжера решаем? ну дык что ее решать 200мс-то? Есть же алгоритм градиентного спуска например.

                                                            > параллельно всему этому идет обмен по Modbus RTU, CAN и RS232.

                                                            этот мусор кто-то еще делает программно? нет? а аппаратно — там же уже некритичны становятся задержки на «общее управление»
                                                            • +2

                                                              Окей. Сделайте вашу лампочку с холодильником и интернетом, тогда поговорим.

                                                            • +1
                                                              > на скорости 4м/с за 5мс лифт проезжает 20см

                                                              Т.е. вы без прерывания хотите ловить момент, когда лифт проезжает условным герконом условный магнитик на стене, по которому определяет место останова?

                                                              > опрос кнопок вызова на этажах и кабине — раз в 20мс. Быстрее не надо и иначе надо отрабатывать дребезг.

                                                              Какой дребезг вы [не] хотите обрабатывать на кнопках в лифте?
                                                              • 0
                                                                Очень просто — опрос кнопки раз в 20мс это и есть реализация алгоритма подавления дребезга(если конечно дребезг кнопки не разрастается больше 20мс), поэтому ничего ДОПОЛНИТЕЛЬНО предпринимать не нужно. А если кнопку опрашивать чаще тогда надо задуматься об дополнительных алгоритмах подавления дребезга… а как там говорится: «лучший код — код которого нет», верно?
                                                                • 0

                                                                  Вопрос был не про «как», а про «зачем», что-то дополнительно предпринимать для защиты от дребезга КНОПОК в ЛИФТЕ.

                                                                  • 0
                                                                    Т.е. вы без прерывания хотите ловить момент, когда лифт проезжает условным герконом условный магнитик на стене, по которому определяет место останова?

                                                                    Да. Мы так делаем уже лет 20, наверное.


                                                                    Вопрос был не про «как», а про «зачем», что-то дополнительно предпринимать для защиты от дребезга КНОПОК в ЛИФТЕ.

                                                                    В лифтах сегодня используются последовательные протоколы для связи между различными контроллерами, например в кабине и на верху. Это сделано для экономии на кабелях. Используются как стандартные, например CANopen, так и свои протоколы на основе RS485. И, например, в CANopen, сообщение на шину посылается по изменению состояния сигнала. Т.е. если не подавлять дребезг, контроллер кнопок будет флудить сообщениями при каждом нажатии.

                                                                    • 0
                                                                      > Да. Мы так делаем уже лет 20, наверное.

                                                                      А это как? «на скорости 4м/с за 5мс лифт проезжает 20см» — метка на стене 20+ см? И лифт останавливается плюс-минус 10см?

                                                                      > Т.е. если не подавлять дребезг, контроллер кнопок будет флудить сообщениями при каждом нажатии.

                                                                      то есть я могу заDDOSить вашу автоматизацию тыкая на разные кнопки в лифте? А просто отключать кнопку, если под ней горит лампочка — не?
                                                                      • 0
                                                                        заDDOSить врятли, с подавлением дребезга физически с одной кнопки нельзя будет выдать больше 50 событий в секунду, а в случае дребезга там могут быть пачки сотнями — успевай только передавать, если конечно передаются сигналы по каждому событию.
                                                                        • 0
                                                                          С одной кнопки может и нельзя, но кнопок то много.

                                                                          > если конечно передаются сигналы по каждому событию

                                                                          Так это главный вопрос: зачем передавать повторные нажатия, хоть сотни, хоть одно через секунду?

                                                                          > заDDOSить врятли

                                                                          Если это максимум уверенности, что могут профессионалы из embedded предложить…
                                                                          • 0
                                                                            Мы же рассматриваем гипотетическую ситуацию. А если сжимать события до порций определённых временных интервалов… это уже будет какая-никакая а отработка дребезга, и стало быть проблема отпадает сама собой.
                                                                            В конце концов, контроллер может быть универсальным и где-то может понадобится информация о всех событиях, хотябы для анализа состояния механики — если какой-то механизм начал давать «дребезг» то это может служить сигналом о необходимости его замены или обслуживания.
                                                                            В случае лифтовых кнопок… ну да, положить систему(не всю систему, а подсистему опроса кнопок) наверно можно будет что она начнёт терять какие-то события и лифт просто будет останавливаться на каждом этаже. Но при этом надо будет стоять у каждой из сотен кнопок и непрерывно нажимать их. Да и наверняка сигналы безопасности и обработки нажатий кнопок разведены по разным шинам и положить всю систему не получится.
                                                                            • 0
                                                                              > Да и наверняка сигналы безопасности и обработки нажатий кнопок разведены по разным шинам и положить всю систему не получится.

                                                                              То есть дребезг системе вообще не страшен? Ок.
                                                                            • 0
                                                                              А это как? «на скорости 4м/с за 5мс лифт проезжает 20см» — метка на стене 20+ см? И лифт останавливается плюс-минус 10см?

                                                                              Не связывайте одно с другим — так мозг сломать можно.


                                                                              Так это главный вопрос: зачем передавать повторные нажатия, хоть сотни, хоть одно через секунду?

                                                                              Так требуется по логике работы. Да, надо передавать повторные нажатия, даже если лампочка уже горит.


                                                                              то есть я могу заDDOSить вашу автоматизацию тыкая на разные кнопки в лифте?

                                                                              Нет.

                                                                              • 0
                                                                                То есть на самом деле всё работает не так, как вы пытаетесь представить.
                                                                                • 0
                                                                                  То есть на самом деле всё работает не так, как вы пытаетесь представить.

                                                                                  Что, например?

                                                                                  • 0
                                                                                    на скорости 4м/с за 5мс лифт проезжает 20см20мм
                                                                                    • 0
                                                                                      Надо ещё учесть что на подъезде к этажу где должен остановиться для более точного позиционирования он снижает скорость. т.е. там не один геркон положения а несколько, и ещё наверняка параллельные цепи на случай выхода из строя контактов.
                                                  • +1

                                                    Не знаю, что вы так вцепились в слово "реалтайм", но есть класс задач, в которых вытесняющие RTOS очень хорошо себя показывают: математика с разделением по приоритетам.


                                                    К примеру, какой-то набор вычислений надо делать на каждую выборку АЦП, при этом когда мы закончили с этой выборкой, можно вернуться к фоновому длинному математическому процессу. Сделать длинный занудный алгоритм вроде БПФ или еще чего кооперативным — проще застрелиться, эти алгоритмы никто не велосипедит, их берут готовыми и они все как один блокирующие до конца выполнения.


                                                    Когда все построено на очередях будет сразу видно состояние overrun, то есть алгоритм не успевает обработать принятые данные.

                                                    • 0
                                                      > Не знаю, что вы так вцепились в слово «реалтайм», но есть класс задач, в которых вытесняющие RTOS очень хорошо себя показывают: математика с разделением по приоритетам.

                                                      дык из пушки по воробъям же.
                                                      недаром в «большом мире» в HighLoad нафиг практически везде шлют это самое вытеснение и строят даже новые языки на том чтоб максимально его НЕ использовать.

                                                      > эти алгоритмы никто не велосипедит, их берут готовыми и они все как один блокирующие до конца выполнения.

                                                      вот уже теплее: то есть пользуемся внешней библиотекой, не поддающейся редактированию. хороший пример, но опять же редкий имхо
                                                      • +2

                                                        Ага, давайте еще перепишем рекурсивный алгоритм на машину состояний.


                                                        практически везде шлют это самое вытеснение

                                                        Ой, да тут все просто — архитектура х86-64 — неповоротливый монстр с тяжеленнейшим контекстом, длинным конвейером и кучей кешей. Его в принципе нельзя отвлекать от важной работы. Получается, что крутиться в цикле while (my_flag.await_condition()) банально быстрее, чем сохранить и восстановить контекст.
                                                        Особенно в многоядерных системах, когда приложение может практически монопольно оккупировать процессорное ядро.


                                                        А теперь берем конкретный пример: железка, которая обслуживает математические вычисления в реалтайме. На этом же процессоре крутится GUI на Qt, сетевые службы и прочая лабудень. Если Qt решит чуть подольше (миллисекунд на 40 так) подержать выполнение потока (а что, пользователь не заметит же) — у меня нарушаются временные рамки реалтаймого процесса.
                                                        И как тут без вытеснения?

                                                        • 0
                                                          > рекурсивный алгоритм на машину состояний

                                                          на AVR?
                                                          • +2

                                                            На Cortex M4F.
                                                            Я пришел в embedded когда мода на атмеги уже прошла.


                                                            Нет, вы не подумайте, я не считаю классическое понятие RTOS с бесконечными циклами чем-то хорошим. Все проекты на RTOS любого вида (хоть вытесняющая, хоть кооперативная) у меня превращались в объекты-диспетчеры сообщений, ожидающие любое из возможных сообщений и, в зависимости от флагов, реагирующие на события.


                                                            Но считать, что вытеснение — зло, это, по меньшей мере, глупо. Как и считать RTOS каким-то монстром, это обычно сишная библиотека из десятка файлов. Просто не нужно думать, что на каждую отдельную лампочку в проекте нужно создавать собственный контекст.

                                                            • 0
                                                              я не считаю что вытеснение зло, я считаю что использовать вытеснение в современных контроллерах в большинстве случаев — стрельба из пушки по воробъям.

                                                              ну а так же в «большом мире» вытеснение в хайлоадах не юзают. и не из за сказки о том что якобы это проблемы x86 архитектуры.
                                                              переключение процессов на ЛЮБОЙ архитектуре будет дорогим. а помимо дороговизны — проблема квантования никуда не денется. проблема IPC.
                                                              почему кооператив работает быстрее? не только потому что дорогое вытеснение, но и потому что IPC дорогой, организация взаимодействия частей программы между собой дорогая.
                                    • 0
                                      В проекте AMS для множества платформ (Mega, Due, 101, M0, ESP8266, ESP32 и т. д.) реализована кооперативная многозадачность, которая позволяет «одновременно» работать десяткам задач, таким как веб-сервер, опрос датчиков и управление актуаторами, приём и передача беспроводных команд nRF24, nooLite и т. п. и в это же время индивидуально управлять положением десятков серв и шаговых моторов — то есть полный фарш и любые прихоти в смысле «многозадачности» на Ардуино. И при этом в веб-интерфейсе стандартного АМС есть индикатор-график в реальном времени показывающий задержки выполнения этой «многозадачности».
                                      Вот примеры работы этой многозадачности в реальных проектах:
                                      https://hi-lab.ru/arduino-mega-server/ams-pro
                                      • 0
                                        эм. по ссылке реклама. а ссылка на код есть?

                                        PS: я вам добавил кармы — может поможет чтобы посты не требовалось модерировать
                                        • 0
                                          Конечно, код для любой платформы можно скачать в разделе загрузок:
                                          https://hi-lab.ru/arduino-mega-server/details/download
                                          • 0
                                            дайте ссылку (название файла) на конкретный модуль кооп многозадачности
                                            я в дороге поразглядываю
                                            • 0
                                              В АМС нет какого-то отдельного «модуля кооперативной многозадачности» или весь код АМС можно назвать таким «модулем». Более того, в АМС нет даже функции yield() или её подобия. То, что реализовано в АМС можно назвать «чистой кооперативной многозадачностью», когда процессы активируются поочерёдно и добровольно отдают управление.
                                              Просто так это конечно работать не будет и там есть много тонких моментов и «трюков» — код доступен и можно посмотреть что и как реализовано. Но в итоге всё работает как часы — зафиксированы аптаймы во много месяцев чёткой и беспроблемной работы.
                                              • 0
                                                > То, что реализовано в АМС можно назвать «чистой кооперативной многозадачностью», когда процессы активируются поочерёдно и добровольно отдают управление.

                                                то есть колбеки? ну я о них в первой части статьи писал :)
                                                • +1
                                                  Из вашей статьи я узнал много новых и интересных терминов. Теперь буду знать как это называется по-научному. :)
                                      • +3
                                        > А давайте притащим мир большого программирования в Arduino!

                                        А давайте не будем этого делать. Давайте оставим хоть где-то «мир маленького программирования». Давайте не будем тащить в diy-сферу мавен, слоноподобные фреймворки, непрерывную интеграцию, разработку через тестирование и прочий буллшит.
                                        Понимаю, статья не об этом, просто начальная фраза зацепила.
                                        • +1
                                          я кстати очень хочу в ардуино непрерывную интеграцию: нужен эмулятор который может управляться скриптами, чтобы автоматические пусть и вирутальные тесты можно было сваять.
                                          • 0

                                            Непрерывная интеграция в embedded натыкается на очень простые препятствия — часто ваш код можно полностью проверить только на реальном железе. А для этого надо лепить аппаратные тестовые стенды, на которых надо выключатели ручками нажимать, которые в непрерывную интеграцию включить не так легко.
                                            Непрерывную интеграцию можно сделать для аппаратно независимых алгоритмов управления, но не для всего контроллера.

                                            • 0
                                              эмулятор контроллера надо писать и давать возможность на скриптах эмулировать внешнюю аппаратуру. тогда CI получится.
                                              • +1

                                                У вас может получиться, что эмуляция внешней аппаратуры может быть сложнее самой программы в МК. Так как для встроенных систем в большинстве случаев надо эмулировать физические процессы, которые они контролируют, а это не так просто, как кажется.

                                                • 0
                                                  У вас может получиться, что эмуляция внешней аппаратуры может быть сложнее самой программы в МК

                                                  а это нормальная ситуация кстати. мы же не сложность программы в МК обсуждаем, а скорость и сложность внесения в нее изменений. возможность получения быстрой обратной связи


                                                  система тестирования ДОЛЖНА быть сложной.


                                                  вот пример из реальной жизни:


                                                  $ find lib|wc -l                       
                                                  751
                                                  $ find t|wc -l  
                                                  2250

                                                  на 751 файл кода библиотек 2250 файлов с их тестами. При этом тестов не совсем достаточно: иногда всплывают таки баги :(

                                                  • +3
                                                    вот пример из реальной жизни: на 751 файл кода библиотек 2250 файлов с их тестами. При этом тестов не совсем достаточно: иногда всплывают таки баги :(

                                                    Сорри, но рассмешили. Вот примеры из реальных систем тестирования встроенных устройств:
                                                    На этапе разработки:
                                                    image
                                                    На этапе производства:
                                                    image
                                                    И все это только для того, чтобы полностью протестировать вон те маленькие коробочки на столе, в которых процессорной мощности может быть меньше чем в вашем ардуино. И все это тестовое оборудование стоит десятки тысяч евро, а его еще нужно собрать, настроить, проверить и написать под него ваши тестовые скрипты. Вы действительно уверены, что CI того стоит?

                                                    • 0
                                                      я говорю о CI в области ПО
                                                      • +2

                                                        В ембеддеде 90% ПО часто завязано на конкретную аппаратную реализацию.


                                                        Даже с сугубо математическими задачами не все так просто: FPU на Intel x64 и оный в TI C2000 ведут себя по-разному в случае, если используются аппаратные ускорители функций (sqrt, sin, и так далее). Одна и та же программа на разных платформах даст разные результаты на одних входных данных.

                                                        • –4
                                                          > В ембеддеде 90% ПО часто завязано на конкретную аппаратную реализацию.

                                                          а вот это не совсем верно.

                                                          вот возьмите скажем софтину работающую с ардуинным модулем WiFi.
                                                          вроде завязано на аппаратуру, так?
                                                          однако если бы был эмулятор, то разве эти команды AT весь набор и ошибок связанных с этим набором нельзя было бы прогнать на автоматических тестах?
                                                          • +1

                                                            AT-команды — это проклятие, а не добро.
                                                            Как минимум потому, что часто документация не соответствует действительности.


                                                            вроде завязано на аппаратуру, так?

                                                            Нет, не завязано. На аппаратуру завязан обмен по UART и управление DMA. Это как раз такой случай, когда (в теории) очень легко покрыть код автотестами. Ну, до тех пор, пока вы не узнаете, что реализация printf (ой, он не выводит float! ой, он не поддерживает int64_t!) различается от компилятора к компилятору и даже внутри оного в зависимости от установленных флагов.

                                                            • 0
                                                              Ну, до тех пор, пока вы не узнаете, что реализация printf

                                                              почему не узнать о том что реализация printf на стадии тестирования ПО а не тестирования железки?

                                                              • 0

                                                                Если подкинете систему автотестов, что умеет сама заливать 25 файлов прошивок в камень, а потом удаленно прогонять автотесты — я буду признателен.


                                                                на стадии тестирования ПО

                                                                Так у нас тестируется на железке или на 86-ом декстопе?

                                                                • 0
                                                                  Если подкинете систему автотестов, что умеет сама заливать 25 файлов прошивок в камень, а потом удаленно прогонять автотесты — я буду признателен.

                                                                  дискуссия началась с чего? с высказывания "давайте не будем в ардуино тащить из большого мира всякую мишуру вроде автотестирования"


                                                                  а я сказал "очень жаль кстати что этого в мире ардуино пока нет"


                                                                  так что если кто-то сделает систему для автотестирования, то я рядышком с Вами тоже признателен буду :)

                                                                  • 0
                                                                    Так у нас тестируется на железке или на 86-ом декстопе?

                                                                    например ARM'ы можно потестировать на 86-м десктопе. посидеть и наладить qemu. теоретически, но можно: эмулятор есть.


                                                                    почему бы не появиться (я мечты же свои озвучиваю) эмулятору для AVR?

                                                                    • 0

                                                                      Меня больше интересуют STM8, TI C28x, TI C66x и прочие монстры (эмуляция последнего может оказаться медленнее прогона на реальном железе). Для некоторых (STM8, C28x) из них я не то, что эмулятора, я компилятора стороннего не видел. А у DSP очень легко нарваться на ошибку конвейера, когда результат операции еще не успел вычислиться, или не успела завершиться операция записи в ОЗУ.

                                                                    • 0

                                                                      Некоторые, кстати, идут в сторону гибридных тестов: https://github.com/japaric/utest (библиотека для работы стандартных растовских unit test'ов в embedded), когда тесты запускаются и на реальной железке через jtag, и на qemu.

                                                                  • 0
                                                                    На аппаратуру завязан обмен по UART и управление DMA.

                                                                    эти вещи по идее можно сделать же на эмуляторе.

                                                                    • +2

                                                                      Для 8051, MSP430 и ARMv6 я эмуляторы еще встречал, но


                                                                      1. это далеко не весь набор платформ, на которых ведется разработка
                                                                      2. обычно эмулируют ядро ЦП, оставляя в стороне детали реализации периферии
                                                                    • 0
                                                                      На аппаратуру завязан обмен по UART и управление DMA

                                                                      в случае WiFi как бы два уровня для тестов:


                                                                      1. тесты на работу с модулем UART
                                                                      2. тесты на работу с WiFi через этот самый UART
                                                                      • 0
                                                                        тесты на работу с модулем UART

                                                                        Довольно бесполезное занятие. Написание теста становится сложнее написания кода, потому что в коде теста придется писать всю инициализацию модуля и сравнивать ее с программной.


                                                                        тесты на работу с WiFi через этот самый UART

                                                                        А вот тут пожалуйста. И микроконтроллер для этого не нужен, если честно.


                                                                        Но это очень легкий пример. Часто периферия выполняет задачи сложнее уровня "передать байт"-"принять байт".

                                                                        • –2
                                                                          > Довольно бесполезное занятие. Написание теста становится сложнее написания кода, потому что в коде теста придется писать всю инициализацию модуля и сравнивать ее с программной.

                                                                          1. если тестовое окружение писать на скриптовом языке — то нет
                                                                          2. написание программы, расчитанной в т.ч. под автоматические тесты часто требует ее реорганизации, это да. Особенно когда автоматические тесты только начинают внедряться. Позже, когда к ним привыкаешь — без них даже код о трех строках кажется ненадёжным

                                                                          > Но это очень легкий пример. Часто периферия выполняет задачи сложнее уровня «передать байт»-«принять байт».

                                                                          если мы поведение периферии задаем на скриптовом языке, почему нельзя сформулировать что-то более сложное?
                                                                          • +3
                                                                            если мы поведение периферии задаем на скриптовом языке, почему нельзя сформулировать что-то более сложное?

                                                                            Не очень понятно, каким боком тут скриптовость языка, но в любом случае, пока вы будете формулировать и отлаживать поведение связки, скажем, таймер-АЦП-ПДП в STM32, другой уже отладит всё в железе и выпустит железку на рынок.

                                                                            Современная периферия это уже не то, что мы привыкли видеть в старых добрых однокристалках типа 8051.
                                                                            • –3
                                                                              > Не очень понятно, каким боком тут скриптовость языка

                                                                              на скриптах просто моделировать сложные вещи

                                                                              > пока вы будете формулировать и отлаживать поведение связки, скажем, таймер-АЦП-ПДП в STM32, другой уже отладит всё в железе и выпустит железку на рынок

                                                                              проблемы у другого начнутся на стадии когда у него сменится нанятый программист, а новый придет и скажет «тут все надо переписывать», «потому что надо».

                                                                              все это растет как раз из за отсутствия CI: из него растет невозможность вносить изменения в собственный код с какого-то уровня развития
                                                                              • –3
                                                                                > пока вы будете формулировать и отлаживать поведение связки, скажем, таймер-АЦП-ПДП в STM32, другой уже отладит всё в железе и выпустит железку на рынок

                                                                                если на русский перевести, то будет известная сказка: «нам пилу точить некогда, нам пилить надо!»
                                                                    • –1
                                                                      В ембеддеде 90% ПО часто завязано на конкретную аппаратную реализацию.

                                                                      вот кстати то что в ембеддеде не занимаются внедрением CI по моему мнению есть причина того что ембеддед программистам так мало платят: они ж до сих пор не смогли свой труд нормально организовать, зачем им платить?


                                                                      PS: не воспримите как оскорбление/наезд, я сам в embedded ~15 лет отработал, пока не ушел в "большой" мир :)

                                                                    • +1

                                                                      Ну вы же хотели применить CI к Ардуино, вроде?
                                                                      А вот представьте себе ситуацию — вы решили немного усовершенствовать софт и добавить туда мигание каким-нибудь светодиодом, который будет подключен к определенной ножке вашего МК. Как вы это будете делать с точки зрения CI?
                                                                      Напомню, что до реализации этого у вас нет ни скриптов, ни тестового стенда (как вы будете проверять мигает светодиод или нет, его период), ни даже самой платы, так как железячники прикрутят светодиод только в следующей ревизии платы.

                                                                      • 0
                                                                        Ну вы же хотели применить CI к Ардуино, вроде?

                                                                        к ардуине в частности и микроконтроллерам вообще


                                                                        Думаю такая компания как скажем Atmel вполне потянула бы написать и поддерживать софт-эмуляторчик для того чтобы его использовать в CI. Причем эмулировать можно прямо все контроллеры AVR: благо там вариантов периферии по пальцам посчитать.


                                                                        А вот представьте себе ситуацию — вы решили немного усовершенствовать софт и добавить туда мигание каким-нибудь светодиодом, который будет подключен к определенной ножке вашего МК. Как вы это будете делать с точки зрения CI?

                                                                        Вы сразу разбираете 100%-й вариант покрытия тестами. к нему можно прийти. но обычно тесты как пишутся? берется некий блок программы, оформляется как библиотека и покрывается тестами.


                                                                        то о чем Вы пишете — это уже интеграционное тестирование, оно как бы поверх юнит-тестирования бывает. Чаще всего бывает в зачаточной форме.


                                                                        если говорить о Вашем светодиоде, то выделяем функцию им управляющую в библиотеку, на эмуляторе запускаем и смотрим состояния меняющиеся по создаваемым тестом условиям

                                                                        • 0
                                                                          то о чем Вы пишете — это уже интеграционное тестирование, оно как бы поверх юнит-тестирования бывает. Чаще всего бывает в зачаточной форме.

                                                                          Это где это оно в зачаточной форме? В эмбеддерстве?

                                                                          • 0

                                                                            в большом мире :)


                                                                            в эмбеддерстве в общем и юниттестирование крайне слабо развито.

                                                                    • 0

                                                                      вот внесли мы изменения в ПО: что дальше? дальше CI прогоняет тесты, когда мы видим что тесты прошли, то только тогда понимаем, что внесенные изменения не приведут к регресси в пределах данной тестовой базы и только после этого доходит до аппаратуры


                                                          • 0
                                                            Давайте не будем тащить в diy-сферу мавен, слоноподобные фреймворки

                                                            мне кажется с Arduino это УЖЕ произошло. Я лет 10 назад программировал AVR. Потом как-то переключился в "большой мир". Сейчас вернулся — есть задачка. Наткнулся на Arduino.


                                                            какие впечатления? МОНСТР.


                                                            • вот ЗАЧЕМ скажите изобретать псевдоязык и расширение файлов .ino? чтобы пользователю не писать include?
                                                            • ЗАЧЕМ C++ повсюду? Чтобы стек получше грузить?
                                                            • ЗАЧЕМ своя GUI-штукенция?

                                                            проект avr-libc был и 10 лет назад. Почему в него не добавить функции с синусами-косинусами, а добавлять их на уровне проекта Arduino?

                                                            • –1
                                                              Мне тоже это непонятно. Но до того, что творится в мире Java, Ардуино еще далеко.
                                                              • +1

                                                                Не понимаю, зачем свой псевдоязык (ладно, это просто C++ с библиотеками), свое расширение и своя GUI-штукенция (отвратная).


                                                                Ардуино — это легкий старт. Не побоюсь признаться, сам начинал с этого.


                                                                Заголовок спойлера

                                                                Хотя, классе в 6-7 пытался что-то сделать на PIC, отлаживая в Proteus. А вот схему простого программатора не нашел, они сами зачастую требовали контроллер, который надо прошить. Ну либо искать тогда не умел.


                                                                Все эти библиотеки — хочешь гироскоп? Вот библиотека. Хочешь NRF24L01 — вот библиотека. Хочешь экран — ну вы поняли. Позволяет сваять какую-то хрень быстро. Ну и вообще, повторное использование кода — это благо. Когда хотел поиграться с LoRa на STM32, пришлось портировать с ардуины библиотеку, ныряя в даташит.


                                                                Вот только многие дальше и не идут, не пытаются глубже понять. А если глубже копнуть, там зачастую такой код, что мама не горюй. И за возможность запустить один и тот же код не то, что на разных AVR, а на AVR, атмеловских ARM, STM32, EPS8266, RTL87xx и черт знает еще на чем, платится низкой скоростью работы и объемом кода. Такой абстрактный-абстрактных HAL. С сильно текущими абстракциями, потому что абстрагироваться от контроллера нельзя. Как было замечено где-то на Easyelectronics, такую универсальную абстракцию и уменьшение сложности можно сделать только отбрасыванием функционала.

                                                                • +1
                                                                  Справедливости ради, никакого псевдоязыка в ардуино нет. Просто некоторые инклуды вставляются перед компиляцией автоматически (и прототипы функций генерируются), а дальше обычный avr-gcc.

                                                                  Основная проблема Ардуины — убогая среда разработки, которая только подсвечивает синтаксис и загружает прошивку, но не умеет ни отладку делать, ни простейший рефакторинг. Я уже не говорю про нормальные многофайловые проекты.

                                                                  Вторая проблема — убогая библиотека, которая прячет слишком много и вызывает привыкание.

                                                                  Третья — убогие восьмибитные атмеги, с которых ардуина никак не может слезть.

                                                                  В С++ самом по себе тоже ничего плохого нет, если уметь им пользоваться, код получается чище/проще/строже, чем на чистом С. Отстрелить себе ногу при этом, разумеется, тоже проще.
                                                                  • 0
                                                                    Справедливости ради, никакого псевдоязыка в ардуино нет. Просто некоторые инклуды вставляются перед компиляцией автоматически (и прототипы функций генерируются), а дальше обычный avr-gcc.

                                                                    ну вот я написал #include <util/atomic.h> — оно мне пожаловалось что "вы компилируете не в стандарте C++".
                                                                    как в GUI это исправить — ХЗ. в Makefile-то я просто CFLAGS нужный добавил.


                                                                    Основная проблема Ардуины — убогая среда разработки

                                                                    тут палка о двух концах: с одной стороны они хотели дать "коробку"
                                                                    с другой они явно не тянули сами IDE делать.


                                                                    В С++ самом по себе тоже ничего плохого нет

                                                                    у меня просто есть проекты на чистом C, я думал туда вклиниться с либой. Поэтому либу хотел на чистом C и сделать.
                                                                    так-то против C++ я тож ничего не имею.


                                                                    Третья — убогие восьмибитные атмеги, с которых ардуина никак не может слезть.

                                                                    дык они ценой же определяются. атмеге всего-то питание подать надо.
                                                                    а ARM'ке одних конденсаторов обвязки килограмм надо повесить, ну и стоить плата будет куда дороже.

                                                                    • 0
                                                                      ну вот я написал #include <util/atomic.h> — оно мне пожаловалось что «вы компилируете не в стандарте C++».
                                                                      как в GUI это исправить — ХЗ. в Makefile-то я просто CFLAGS нужный добавил.

                                                                      Ну только это не проблема языка, это убогая система сборки. Это да, никаких возражений.

                                                                      дык они ценой же определяются. атмеге всего-то питание подать надо.
                                                                      а ARM'ке одних конденсаторов обвязки килограмм надо повесить, ну и стоить плата будет куда дороже.

                                                                      Но при этом сам чип армовый может быть и дешевле атмеги. Насчет платы и обвязки говорить не могу, не знаю.
                                                                      • 0
                                                                        вот выпускали бы армовые чипы о 32-х ножках, с тремя таймерами на борту и с RAM/Flash/EEPROM, USART и прочим, при той же стоимости что и AVR, кто б вспомнил об AVR?
                                                                        • 0
                                                                          Если исключить требование EEPROM (в stm его вроде бы нигде нет), то чипы вроде stm32f030k6, stm32f031k6 подходят по остальным требованиям и должны стоить в районе доллара за штуку. Есть в LQFP32.

                                                                          О цене аналогичных AVR судить не берусь.
                                                                          • 0
                                                                            прекрасные кристальчики, вот на них бы проект аля ардуино: 256К flash и 32К RAM на борту и корпус можно самому запаять.

                                                                            вот бы ардуино на таком :)
                                                                            • 0
                                                                              Так ведь есть же. Есть она, ардуина на STM32. давно уже пару платок заказал, лежат руки никак не дойдут.
                                                                            • 0
                                                                              интересно, аналог AVR-LIBC для них есть? то есть набор заголовков ориентированный именно на контроллеры?
                                                                              • 0
                                                                                Есть microlib и nanolib. Вообще, есть gcc для arm-none-eabi таргета, он вполне прилично компилирует. У проприетарных компиляторов получается немного лучше, но не на порядок.
                                                                                • 0
                                                                                  Если линкеру сказать --specs=nosys.specs и --specs=nano.specs.
                                                                      • 0
                                                                        Ответ на все «ЗАЧЕМ» — чтобы понизить порог входа.
                                                                        Вам-то что, вы уже знакомы с техникой и не представляет проблемы настроить среду(блокнот с подсветкой?), настроить компиляцию под конкретный проект, взять нужный программатор и т.д. в случае ошибок/непоняток вы точно знаете что гуглить и куда смотреть.
                                                                        Но поставьте себя в роли новичка, который видит это всё в первый раз и норовит подключить светодиод напрямую к батарейке…
                                                                        Попробуйте например через неделю провести хирургическую операцию, даже при условии доступности всей обучающей литературы. Предполагается что АРДУИНА, со всей своей требухой, это временная стартовая площадка после которой переходят к полноценным компиляторам. Но некоторые всё-таки не переходят а так и остаются…
                                                                      • 0
                                                                        Ну как сказать. Помнится, когда-то давно делали мы замерные установки и устройства контроля скважинных насосов для нефтегазодобычи, в качестве базы были в половине случаев x86-совместимые крохотные контроллеры, во вторых случаях вообще свои приборы на STM8/STM32, и вот знаете, в связи с постоянно меняющимися требованиям от заказчиков, частыми релизами, и необходимости тащить обратную совместимость с десятком изделий многолетней давности, непрерывной интеграции и разработки через тестирование там реально не хватало. Микрофреймворк свой в итоге сами написали (например там даже было что-то типа dependency injection, и возможность гонять тесты как на целевой платформе, так и на ПК), деплой на сотню устройств на нефтепромысле по радиоканалу после сборки и прохождения тестов тоже сделали, правда, в полуавтоматизированном виде (ограничения там были скорее административные, а не технические). Так что это не «буллшит», многие вещи из мира «большого ПО» в мире встраиваемых систем могут принести достаточно пользы, если знать как их использовать и использовать с умом.

                                                                        А у некоторых промышленных контроллеров так вообще есть многозадачность «из коробки», (например, SCADAPack с VxWorks на борту) — в некоторых задачах это довольно хорошо упрощало код.
                                                                        • +2
                                                                          Согласен. Бизнесу такой подход приносит очень большую пользу. Лично мне — нет. Сейчас профессия программиста незаметно превращается в профессию конфигуриста. Это не интересно.
                                                                          • 0

                                                                            Точная фраза, возьму на вооружение.

                                                                      • +1
                                                                        Каждом свое. Это не мой вариант; такого «добра» мне на работе хватает. Я вроде как программист, и в трудовой написано, что программист, но фактически приходиться разбираться с кучей посторонних вещей, не имеющих непосредственное отношение к программированию. Боюсь, что через несколько лет с Ардуино сложится такая же ситуация: новичку нельзя будет просто открыть IDE и, написав пару строк, поморгать светодиодом. Нет, надо будет развернуть систему сборки, завести репозиторий на гитхабе, и, спустя неделю, перелопатив гугл вдоль и поперек, найти ответ (или намек, что бывает чаще), почему все это не работает.
                                                                        • 0
                                                                          У нас есть Ардуино 1.6.5 и никакие нововведения нам не страшны :) (шутка)
                                                                          • 0

                                                                            дык оно УЖЕ:


                                                                            я поставил Arduino 1.0.5, заработало пусть и вот с такими кривыми шрифтами



                                                                            чтобы исправить те шрифты надо залезть куда-то в Java.


                                                                            я поигрался — написал тот самый светодиод, сохранил проект, но шрифты… да
                                                                            посмотрел — в "большом" мире уже Arduino 1.5.
                                                                            заглянул в Debian/experimental — там 1.5 есть — установил.


                                                                            во первых GUI банально не запустился (еще не разбирался)
                                                                            а во вторых Arduino.mk теперь имеет другие переменные управления что-то в области BOARD_SUB поменяли, хз.


                                                                            то есть проект который я 10 минут назад компилял в 1.0.5 в 1.5 уже не собирается.


                                                                            и вот как скажите программисту Arduino не разбираться с кучей посторонних вещей?

                                                                            • 0
                                                                              Устанавливал недавно Arduino IDE под Linux Mint. Тоже GUI не запускался. Проблема была в том, что ставил его под рутом, а надо было под своим пользователем.
                                                                              • 0
                                                                                > Проблема была в том, что ставил его под рутом, а надо было под своим пользователем.

                                                                                установка ПО под пользователем — то еще зло. есть вещи которые я не могу делать. все внутри протестует.
                                                                                и одна из этих вещей — скачивание бинарников пользователем и запуск их :)
                                                                                поэтому сижу с 98-го года в Linux :)
                                                                                • 0
                                                                                  Как-то странно получается: программы ставить только из-под рута? Почему?! И что значит «частота Linux 1000 Гц»? Частота чего? Если планировщика, то там сейчас нет фиксированной латентности планировщика и фиксированного кванта для процессов. При этом потоку в среднем будет дано около 100 мсек, если нет более приоритетного конкурента. Если я не путаю, я все-таки прикладной программист.
                                                                                  • 0
                                                                                    Как-то странно получается: программы ставить только из-под рута? Почему?!

                                                                                    дело не в руте, дело в репозитариях

                                                                          • 0
                                                                            Вы просили: «Реальных тредов в том понимании как их понимают в „большом“ мире я не нашел. Буду благодарен, если кто-то подбросит мне ссылку на такой проект.»
                                                                            Вот: github.com/scmrtos/scmrtos
                                                                            • 0
                                                                              судя по документации шикарная штучка, спасибо, попробую ее
                                                                              • 0
                                                                                Там есть красивый документ на русском языке от создателей.
                                                                                Во всех смыслах прекрасная вещь

                                                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.