рассуждения на тему state machine

Общие принципы, проектирование, модуляризация, темплейты и шаблоны
Artem.spb

Activity Автор
professor
professor
Сообщения: 3394
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

рассуждения на тему state machine

Сообщение Artem.spb »

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

Обобщённая задача такова:
Оборудование (оно же «внешний мир»)
  • Данные 1. частота 10 Гц.
  • Данные 2. Частота опроса 1 Гц
  • Данные 3. Приходят в случайное время (например, чтобы было понятнее: счётчик с внешним запуском, запуск происходит в случайное время)
  • Исполнительный механизм 1. Время реакции на запрос неопределённо, получив команду, исполняет её и отправляет отчёт.
  • Исполнительный механизм 2. аналогично.
  • Ну и UI
Упрощённая SM
  • сост 1. отображение только новых данных 1, 2 и 3 (желательно только тот тип, что пришёл). Переход в 2 по команде пользователя.
  • сост 2. анализ данных 1. при некоторых значениях перейти в 3. При других – в 4.
  • сост 3 отправить команду на ИМ1. после прихода подтверждения перейти в 5
  • сост 4 обработка Д3. переход в 5 или 2 в зависимости от значения
  • сост 5. ИМ2. после прихода подтверждения перейти в 6
  • сост 6. Диалог с пользователем. Переход в 7 или 2.
  • сост 7. ИМ1. после прихода подтверждения перейти в 2.
Ну и параллельно со всем этим, как и в состоянии 1 обновление экрана при приходе новых данных и возможность прерывания хода пользователем (т.е. по команде корректных выход из всех состояний в первое)
Безымянный.png
Я решаю эту задачу так:
Создаю юзер-события на каждый тип данных (Д1-3) и подтверждения от ИМ.
В машине состояний использую event-структуру. В shift-регистре храню состояние машины.
В разных евентах проверяю текущее состояние. Если «правильное», то выполняю требуемые действия (в том числе меняю значение состояния).
При этом, естественно, в каждом event есть case с пустыми кейсами «по умолчанию».
Аватара пользователя
Vasiliy Baev

Activity Gold Bronze
leader
leader
Сообщения: 545
Зарегистрирован: 31 окт 2011, 09:02
Награды: 4
Версия LabVIEW: 2019
Откуда: Санкт-Петербург
Благодарил (а): 8 раз
Поблагодарили: 10 раз
Контактная информация:

Re: рассуждения на тему state machine

Сообщение Vasiliy Baev »

Artem.spb, привет!
Рекомендую для такого рода задач использовать очереди, уведомления (http://www.labviewportal.org/viewtopic.php?f=84&t=9038)

Задачу разбить на различные циклы:
- Display (Отображение данных)
- Event Structure (обработка кнопок на экране)
- DAQ (циклы сбора данных)
- Обработчик данных
и так далее

Для каждого цикла своя очередь.

Вот к примеру как у меня выглядит VI верхнего уровня на контроллере cRIO.
CRIO.png
Каждый цикл своя задача. Где-то работаем по событию (приход новых данных), где с определенной частотой... В каких-то циклах крутятся машины состояний...

Я так делаю давно, в чем-то это напоминает Actor Fraimwork - с которым познакомиться руки так и не дошли.
Кода стало больше, много больше, но отлаживать его стало проще.

Добавлено:
А вообще, вот руководство к действию в таких задачах: http://www.labviewportal.org/viewtopic.php?f=23&t=153
В свое время эта тема мне очень помогла.
Artem.spb

Activity Автор
professor
professor
Сообщения: 3394
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

Re: рассуждения на тему state machine

Сообщение Artem.spb »

Рекомендую для такого рода задач использовать очереди, уведомления (http://www.labviewportal.org/viewtopic.php?f=84&t=9038)
Vasiliy, такие примитивы мне знакомы уже не первый десяток лет :)
но вот с очередями я не согласен, я вместо них как раз использую user-event. На каждый тип свой евент.
Это с одной стороны увеличивает количество типов событий, но с другой упрощает обработку по кейсам - не надо парсить строку с данными и разбираться, что же там пришло и как этими данными следует воспользовтаься (отправить их на график, или совершить переход в другое состояние)
Вот к примеру как у меня выглядит VI верхнего уровня на контроллере cRIO.
Вложение CRIO.png больше недоступно
Каждый цикл своя задача. Где-то работаем по событию (приход новых данных), где с определенной частотой... В каких-то циклах крутятся машины состояний...
... а ещё нужна обработка UI. Её сложно (хоть и можно) отправить в subVI, поэтому у меня БД выглядят примерно так
BD.png
В принципе именно необходимость обрабатывать действия пользователя и привела сначала к использованию event (контролы), а позже к ним добавились события, генерируемые параллельными потоками (те самые потоки взаимодействия с железом). Таким образом обработчиком SM у меня является цикл обработки действий пользователя.

Ваше описание по сути (кроме queu-event) не отличается от моего.
Тут можно запустить параллельную дискуссию, что лучше: очереди или события в таких ситуациях.
rbl
assistant
assistant
Сообщения: 122
Зарегистрирован: 09 дек 2014, 10:14
Версия LabVIEW: 7-2015
Откуда: Санкт-Петербург
Контактная информация:

Re: рассуждения на тему state machine

Сообщение rbl »

Artem.spb писал(а):
Рекомендую для такого рода задач использовать очереди, уведомления (http://www.labviewportal.org/viewtopic.php?f=84&t=9038)
Vasiliy, такие примитивы мне знакомы уже не первый десяток лет :)
но вот с очередями я не согласен, я вместо них как раз использую user-event. На каждый тип свой евент.
Это с одной стороны увеличивает количество типов событий, но с другой упрощает обработку по кейсам - не надо парсить строку с данными и разбираться, что же там пришло и как этими данными следует воспользовтаься (отправить их на график, или совершить переход в другое состояние)
Работа с очередями >=20 лет это сильно...
Я бы не назвал решение с очередью примитивом, особенно для тех скоростей, которые Вы привели. Вполне себе элегантное решение с одной очередью, 3 префикса для для события, простой конечный автомат с парсером на входе.
Легко кодить, легко читать, надежно работает... изи мани
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: рассуждения на тему state machine

Сообщение Borjomy_1 »

Artem.spb писал(а):
но вот с очередями я не согласен, я вместо них как раз использую user-event. На каждый тип свой евент.
Это с одной стороны увеличивает количество типов событий, но с другой упрощает обработку по кейсам - не надо парсить строку с данными и разбираться, что же там пришло и как этими данными следует воспользовтаься (отправить их на график, или совершить переход в другое состояние)
Не понял, почему очередь нужно парсить. Очереди спокойно назначается нужный формат данных. Эвент это та-же очередь, только значительно хуже управляемая. Сравните палитры Events и Queue Operations.
И вообще, визуализация и машина состояний это совершенно разные задачи. И их следует обрабатывать в разных потоках.
Artem.spb

Activity Автор
professor
professor
Сообщения: 3394
Зарегистрирован: 31 июл 2011, 23:05
Награды: 2
Версия LabVIEW: 12-18
Благодарил (а): 49 раз
Поблагодарили: 172 раза
Контактная информация:

Re: рассуждения на тему state machine

Сообщение Artem.spb »

rbl писал(а):Я бы не назвал решение с очередью примитивом
Примитивами в данном контексте называются базовые функции. В этом смысле plus и read queue - примитивы.
Borjomy_1 писал(а):
Artem.spb писал(а):
но вот с очередями я не согласен, я вместо них как раз использую user-event. На каждый тип свой евент.
Это с одной стороны увеличивает количество типов событий, но с другой упрощает обработку по кейсам - не надо парсить строку с данными и разбираться, что же там пришло и как этими данными следует воспользовтаься (отправить их на график, или совершить переход в другое состояние)
Не понял, почему очередь нужно парсить. Очереди спокойно назначается нужный формат данных. Эвент это та-же очередь, только значительно хуже управляемая. Сравните палитры Events и Queue Operations.
МС принимает данные от нескольких источников. Если делать очередь на каждый тип данных, то в одном цикле придётся проверять несколько очередей, это будет вовсе жутко выглядеть. Если брать одну очередь, то придётся парсить.
События можно обрабатывать каждое в своём кейсе, при этом все кейсы собраны в одну структуру
И вообще, визуализация и машина состояний это совершенно разные задачи. И их следует обрабатывать в разных потоках.
на мой взгляд это не строгое заявление. В некоторых случаях можно совместить.
К тому же в разных состояниях может потребоваться разное отображение даже одних и тех же данных. Тогда придётся заводить МС ещё и в потоке визуализации.
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: рассуждения на тему state machine

Сообщение Borjomy_1 »

Если брать одну очередь, то придётся парсить.
Ну парсить. Как будто это так сложно! Есть в конце концов, известный класс Taskings2.
События можно обрабатывать каждое в своём кейсе, при этом все кейсы собраны в одну структуру
Моя практика говорит о том, что для серьезных задач так делать категорически нельзя (просто потом все равно придется переделывать). И вот почему: когда вы в событии должны выполнять работу со внешним устройством, вы должны быть готовы, что этот обмен выполняется неопределенное время. Даже выделив этот код в отдельную функцию, все равно не удастся избавиться от блокировки потока на время обмена.
2. Перекрестные запросы невозможны в рамках одного потока.

Структурно программа может быть выполнена следующим образом: для каждого объекта создается свой поток (на основе Taskings2). Объектом являются части программы - визуализация, архивирования, алгоритм, ввод-вывод, сбор готовностей и прочее. Обмениваются они событиями. И все прекрасно реализуется на очередях. Если необходимо выполнить запрос данных из другого потока, то в запросе передается ref на предварительно созданную очередь или нотификатор. Когда запрос выполнен, результаты передаются обратно через него (таким образом, например, можно обеспечить данными диалоги настроек объектов). Но обычно обмен идет через очереди, без обратного потока. Для сбора необходимо управление - загрузка настроек, поддержка актуального соединения, результат - выдача данных на алгоритм, в архив, может быть на визуализацию, на сборку готовностей системы. Поток алгоритма принимает данные от датчиков (может быть и по отдельным потокам, например FIFO), выдает результат на визуализацию, в архив, и в готовности. И т.д каждый компонент. Для всех может быть реализована загрузка настроек, инициализация, останов через глобальные команды. Таким образом получаем быстродействующую слабо потоко-зависимую систему, с возможностью масштабирования.
Upd. Блин... подробное расписывание этой структуры может потянуть на кандидатскую...
rbl
assistant
assistant
Сообщения: 122
Зарегистрирован: 09 дек 2014, 10:14
Версия LabVIEW: 7-2015
Откуда: Санкт-Петербург
Контактная информация:

Re: рассуждения на тему state machine

Сообщение rbl »

Artem.spb писал(а): Если брать одну очередь, то придётся парсить.
Что плохого в парсере? Написали, заинлайнили и работает, как часы. У меня в одном проекте реализован парсер входного буфера (~1Kb) парсится на ~200 параметров и все это занимает меньше микросекунды...
В чем профит усложнения структуры - я категорически не понимаю.
Аватара пользователя
Vitekkz88

Activity Silver Автор
expert
expert
Сообщения: 1100
Зарегистрирован: 21 янв 2014, 15:45
Награды: 3
Версия LabVIEW: 12,13,14
Откуда: Томск
Контактная информация:

Re: рассуждения на тему state machine

Сообщение Vitekkz88 »

"Что лучше? очереди или User Event" тема древняя, на форуме офицалов разработчики не давали однозначного ответа, что лучше. Одни за User Event были, как за более гибкую на их взгляд технологию. Других не парило и на очередях всё делать. Я сам научился на очередях и меня всё устраивает. Да, в User Event-ах можно не греть голову с утечкой памяти. На очередях тоже, впринципе, если реализация нормальная. Ну и очередей наверно создавать нужно по-более, нежели регистраторов событий.
Если в определенный момент поставят перед фактом, что User Event круче очередей, то подумаю над их использованием. Меня больше интересует схожесть/отличия очередей в LabVIEW/С++. А так же, кто и как часто пользуется в LabVIEW семафорами, например.
Про парсинг я не вкурил... Зачем? Вот у меня созданы N очередей. Часть на приём данных(данные принимаются как string). С других устройств в виде массива байт. Другие очереди содержат команды. Не вижу смысла экономить 3-4 очереди, чтобы объединить их в одну но добавить парсинг по некоторому дескриптору. Тоже наверно дело вкуса/привычки, не?
Инженер - это открыто светящийся интеллект, свободный и не обидный юмор, это легкость и широта мысли...Это воспитанность, тонкость вкусов, хорошая речь, плавно согласованная и без сорных словечек...
-А. И. Солженицын
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: рассуждения на тему state machine

Сообщение Borjomy_1 »

Vitekkz88, Парсинг нужен, когда одна очередь обслуживает объект, т.е принимает код команды и данные. Данные получаются контекстно зависимыми от команды, их и парсят.
rbl
assistant
assistant
Сообщения: 122
Зарегистрирован: 09 дек 2014, 10:14
Версия LabVIEW: 7-2015
Откуда: Санкт-Петербург
Контактная информация:

Re: рассуждения на тему state machine

Сообщение rbl »

Vitekkz88 писал(а): Про парсинг я не вкурил... Зачем? Вот у меня созданы N очередей. Часть на приём данных(данные принимаются как string). С других устройств в виде массива байт. Другие очереди содержат команды. Не вижу смысла экономить 3-4 очереди, чтобы объединить их в одну но добавить парсинг по некоторому дескриптору. Тоже наверно дело вкуса/привычки, не?
Решение конкретно под эту задачу. Заказчику нужно легко читаемый конечный автомат и есть 3 события одного типа данных. По мне так тут решение с одной очередью и парсером самое то. Но, наверное, Вы правы. Это вкусовщина...
Аватара пользователя
Kosist

Activity Gold
expert
expert
Сообщения: 1236
Зарегистрирован: 21 фев 2011, 23:44
Награды: 2
Версия LabVIEW: 2013-2020
Благодарил (а): 23 раза
Поблагодарили: 30 раз
Контактная информация:

Re: рассуждения на тему state machine

Сообщение Kosist »

Vitekkz88 писал(а):"Что лучше? очереди или User Event" тема древняя, на форуме офицалов разработчики не давали однозначного ответа, что лучше.
По моему, все зависит от того, что нужно делать. Не стоит забывать, что User Event - это Multiply Readers, Multiply Writers; а очередя - это Multiply Writer, Single Reader.
На форуме уже обсуждали и JKI State Machine, в которой обработка событий + евент структура + стейт машина находятся в одном While Loop. И, помнится, большинством был сделан вывод, что это - нехорошо, т.к. пихать алгоритмы внутрь евент струкруты, и тем самым делать ее потенциально "замедленно" на интеракцию с юзером - плохо. Вспомните, как виснет VIPM, когда при первом запуске загружает список приложений; или при самой установке тулкитов...
Я видел приложение, где чтение с двух девайсов было навешено на User Event, который обрабатывался в одной виайке. И как результат - приложение нужно было переписать, т.к. в то время, когда один девайс передавал данные, второй не мог "пробиться" через очередь событий, и юзер не мог толком управлять приложением, т.к. само собой, полученные данные нагружали Event Structure еще и временем их обработки.
Artem.spb писал(а):МС принимает данные от нескольких источников. Если делать очередь на каждый тип данных, то в одном цикле придётся проверять несколько очередей, это будет вовсе жутко выглядеть. Если брать одну очередь, то придётся парсить.
События можно обрабатывать каждое в своём кейсе, при этом все кейсы собраны в одну структуру.
А что мешает создать для каждого источника данных свой кейс при использовании очередей? У Вас что так, что так получается дубликация кода. По такой логике, Вы же можете и через один User Events передавать данные + их источник, и делать парсинг. Но так не делаете, т.к. на каждый источник у Вас свой юзер евент. Но ведь то же самое можно сделать с очередью - через одну очередь передавать данные с разных источников на разные страницы кейс-структуры.
Мы делили апельсин - много наших полегло...
Blackman

Activity
leader
leader
Сообщения: 932
Зарегистрирован: 17 янв 2016, 15:02
Награды: 1
Версия LabVIEW: 6.1,8.5,20

Re: рассуждения на тему state machine

Сообщение Blackman »

Kosist писал(а):... Вспомните, как виснет VIPM, когда при первом запуске загружает список приложений; или при самой установке тулкитов...
О каком "подвисании" идет речь? Обыкновенная загрузка базы данных и подготовка интерфейса пользователя перед началом работы. По пути проверка доступных обновлений. Что может делать пользователь пока эти операции алгоритма работы программы не будут выполнены?
По events: с какой целью они были реализованы в DAQmx? А что кто то, где то, как то не смог пробиться к events structure, так это ни как не указывает на ее мифические недостатки, а говорит только об уровне программиста.
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2210
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: рассуждения на тему state machine

Сообщение Borjomy_1 »

О каком "подвисании" идет речь? Обыкновенная загрузка базы данных и подготовка интерфейса пользователя перед началом работы. По пути проверка доступных обновлений.

О таком, что пока все не подгрузится, интерфейс программы недоступен. Даже закрыть нельзя. Явный промах, ибо загрузка базы (с коннектом к удаленному серверу) занимает очень много времени.
Что может делать пользователь пока эти операции алгоритма работы программы не будут выполнены?

Пользователя неплохо было-бы информировать о том, что в данный момент происходит и не блокировать интерфейс.
По events: с какой целью они были реализованы в DAQmx? А что кто то, где то, как то не смог пробиться к events structure, так это ни как не указывает на ее мифические недостатки, а говорит только об уровне программиста.
Ага.. Только NI не рекомендует использовать несколько Events Structure, запущенных одновременно (это ведь уже проходили - в зависимости от того, какая структура активна, ей и идут возникающие события). В таких условиях ее использование для обработки и реакции пользователя и работы с устройствами, это неправильный выбор инструмента. И разработчик может хоть обквалифицироваться, но от недостатков решения далеко уйти не сможет.
Я что-то User Events не встречал DAQmx. Он принимает их или выдает? Если выдает, то это вообще к рассматриваемому нам вопросу отношения не имеет. Событие, которое выдает устройство, может, и надо ждать. Но это не означает, что реакция на него всегда требует ожидания. Да и подумайте сами: кто в обработчике событий делает схему "запрос-ответ"? Наверное, полный неуч, потому что в реакция на событие должна быть минимальная по времени.
Аватара пользователя
Vitekkz88

Activity Silver Автор
expert
expert
Сообщения: 1100
Зарегистрирован: 21 янв 2014, 15:45
Награды: 3
Версия LabVIEW: 12,13,14
Откуда: Томск
Контактная информация:

Re: рассуждения на тему state machine

Сообщение Vitekkz88 »

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

Вернуться в «Модели программирования»