|
|
  |
State machine, Приведите примеры реализации |
|
|
|
Mar 13 2009, 21:30
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Dog Pawlowa @ Mar 11 2009, 09:18)  LOL : чуть дальше "Но реально не применяю :-), как-то не жмёт пока обычный switch()... " По крайней мере я не пользуюсь этой возможностью не потому, что я о ней не знаю :-) Мне просто не нужен эффект от неё, а я с какого-то фига стараюсь не использовать нечто очень специфическое - хотя иногдасамому непонятно почему. Используют же работающие с IAR его всякие красивости и в ус не дуют. Впрочем, потихоньку прорывает, недавно таки поставил диапазонный case там, где он был удобен, чуть раньше локальную (вложенную) функцию использовал там, где она очень просилась.В подобных же темах часто обсуждается как бы выжать ещё немного объёма и скорости и в таком месте вычисляемый goto вполне в строку. Имеет общие черты как функцй, возвращющих указатели на фунции, так и switch
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 14 2009, 13:07
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Diz @ Mar 14 2009, 13:13)  Интересно, а как сделать с набором параллельно работающих конечных автоматов (без RTOS) долго работающую задачу, требующую активного участия процессора ? Например, работу с FAT (сектор может читаться значительное время) или рендеринг экрана для UI (тоже небыстро). Разбивать на отдельные этапы некрасиво и неудобно, а иначе задача будет блокировать другие на долгое время. Да, есть некоторая проблема. Там, где обращение к УВВ гробит интерфейс пользователя, делаем упреждающее чтение в память при включении устройства (ну типа Windows  ). Там где это невозможно... ну работали же раньше с дискетами? Часики, песочек...
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Mar 15 2009, 09:26
|
Частый гость
 
Группа: Участник
Сообщений: 84
Регистрация: 1-08-06
Пользователь №: 19 250

|
Цитата(singlskv @ Mar 15 2009, 01:23)  Разбивать на этапы, и других вариантов особо и нет... Ну или хитрое разделение с задачами выполняемыми в прерываниях. Вообщем, для таких вещей напрашивается RTOS. Или разделение на несколько процессоров, если задача позволяет.
Сообщение отредактировал Diz - Mar 15 2009, 09:27
|
|
|
|
|
Mar 17 2009, 20:14
|
Частый гость
 
Группа: Участник
Сообщений: 84
Регистрация: 1-08-06
Пользователь №: 19 250

|
Еще один интересный вариант реализации машины состояния на плюсах, использовали в одном проекте.
Каждое состояние представляется отдельным классом, унаследованным от базового. Все обработчики событий заданы в базовом классе как виртуальные функции: virtual void eventButtonPressed() = 0 ; virtual void eventTimerExpired() = 0 ;
Определяются конкретные обработчики уже в производных классах (состояниях). Также существует указатель, указывающий на текущее состояние (экземпляр класса). По приходу события просто вызывается нужная функция-член из класса по указателю.
Преимущества:
Базовый класс не обязательно должен быть абстрактным. Некоторые обработчики можно сразу определить в нем и получить реакцию на событие по умолчанию. Как пример, обработчик тика системного таймера, на который надо реагировать одинаково во всех состояниях.
Можно сделать более сложную иерархию классов. Унаследовать класс от базового, определить в нем обработчик (напр. eventPacketReceived). От этого класса наследовать еще несколько подсостояний, но там этот обработчик не определять. В итоге подстостояния унаследуют реакцию на eventPacketReceived от своего суперкласса. Получается простая реализация иерархической машины состояний.
Можно инкапсулировать в класс данные, нужные только для конкретного состояния - например, счетчик принятых пакетов.
Вменяемый плюсовый компилятор делает очень хороший код с оптимизацией - на такие задачи он и рассчитан, вообщем-то.
Хорошие IDE умеют показывать иерархию классов, что приятно для визуализации во время кодирования.
Недостатки:
Много писанины, много однострочных функций. Наглядности без визуализации IDE никакой.
Требуется еще одна таблица или switch для выбора метода по приходу события.
Компилятор может оказаться невменяемым :-)
|
|
|
|
|
Mar 19 2009, 20:12
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Diz @ Mar 15 2009, 12:26)  Вообщем, для таких вещей напрашивается RTOS. Или разделение на несколько процессоров, если задача позволяет. Какой нафиг RTOS...  вот буквально последняя задачка, опрос 6 дискретов с тактом 50мкс с фильтрацией (это быстрый процесс) и обмен по уарт на 230400("медленный" процесс), обмен при этом на скорости ~19Кбайт/сек все решает точное деление на состояния автомата обмена по уарту...
|
|
|
|
|
Mar 19 2009, 21:32
|
Частый гость
 
Группа: Участник
Сообщений: 84
Регистрация: 1-08-06
Пользователь №: 19 250

|
Цитата(singlskv @ Mar 19 2009, 23:12)  Какой нафиг RTOS...  вот буквально последняя задачка, опрос 6 дискретов с тактом 50мкс с фильтрацией (это быстрый процесс) и обмен по уарт на 230400("медленный" процесс), обмен при этом на скорости ~19Кбайт/сек все решает точное деление на состояния автомата обмена по уарту... Ну, это деление не этапы опять же :-) Иногда хочется использовать готовую библиотеку (для того же FAT) - бить на состояния уже непросто. Проще даже переписать с нуля.
Сообщение отредактировал Diz - Mar 19 2009, 21:35
|
|
|
|
|
Mar 20 2009, 20:10
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Dog Pawlowa @ Mar 20 2009, 12:05)  Да, большие готовые библиотеки лишают автоматы всяческих преимуществ... Однако тупик с автоматами... Не, не всегда так все печально..., если есть "жирная"(библиотечная в том числе) функция, то она работает в основном цикле проги, автоматы просто выносятся в прерывания, например в прерывания системного тика (10мс, 1мс, 100мкс, 25мкс...) Конечно при этом нужно "вручную" рулить приоритетами и занимаемым автоматами временем, но как бонус, 100% загрузка проца и максимальные параметры по автоматам(при удачном ручном распределении) Вобщем особых ограничений к использованию автоматов все равно не просматривается.... есть только частные ограничения реализации.
|
|
|
|
|
Mar 22 2009, 04:53
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Diz @ Mar 14 2009, 11:13)  Интересно, а как сделать с набором параллельно работающих конечных автоматов (без RTOS) долго работающую задачу, требующую активного участия процессора ? Например, работу с FAT (сектор может читаться значительное время) или рендеринг экрана для UI (тоже небыстро). Разбивать на отдельные этапы некрасиво и неудобно, а иначе задача будет блокировать другие на долгое время. ..... С FAT пример неудачен. Сектор то читается драйверком SPI, и пока он читается задача отдыхает (не требует активного участия CPU). Рендеринг экрана - подходящий пример. Посмотрим по аналогии. Есть Borland'овский VCL, где вся графика обслуживается исключительно в основном потоке приложения, и при запуске какой-то длительной задачки в том же основном потоке прорисовка приложения намертво тормозится. Чтобы пользователь не подумал, что программа зависла, можно и нужно было либо стартовать доп поток, либо, что значительно проще - иногда вызвать функцию: Application->ProcessMessages(); Вот так же можно поступить и тут. Что мешает реализовать некую функцию yield / idle - которую любой затяжной процесс сможет вызвать сам, чтобы дать поработать всем остальным процессам? Для того чтобы такую функцию можно было реализовать, необходимо чтобы был список задач(автоматов) с возможностью модификации в Run-Time (чтобы процесс вызывающий эту функцию мог быть удален из списка процессов на время своего испонения). Сосбно вот: CODE typedef void (* p_cb)(void);
#define COUNT(arr) (sizeof(arr) / sizeof((arr)[0]))
p_cb list[4];
void add_task( p_cb Callback) { for(int i = 0; i < COUNT(list); i++) if (!list[ i ]) { list[ i ] = Callback; break; } }
void idle(void) { for(int i = 0; i < COUNT(list); i++) if (list[ i ]) { p_cb cb = list[ i ]; list[ i ] = NULL; cb(); list[ i ] = cb; } }
void foo_1(void) { }
void foo_2(void) { }
// это долгий процесс делающий рендеринг void foo_long(void) { volatile unsigned long x = -1UL; while( x--) { // ... do complex stuff
if ( (x & 0xFF) == 0 ) // 255 iterations passed { // дадим поработать другим задачам idle(); } } }
void main(void) { add_task( foo_1 ); add_task( foo_2 ); add_task( foo_long ); for(;;) idle(); } Цитата Да, большие готовые библиотеки лишают автоматы всяческих преимуществ... Однако тупик с автоматами... Раскидать idle()'ов по ключевым точкам и автоматы получают вторую жизнь.
Причина редактирования: Уменьшение видимого размера цитаты исходника.
|
|
|
|
|
Mar 23 2009, 09:57
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(defunct @ Mar 22 2009, 07:53)  Раскидать idle()'ов по ключевым точкам и автоматы получают вторую жизнь. Конкретный пример. Готовая библиотека efsl. Вставка готового порта заняла час. Как по быстрому применить автомат для разделения процессов? Потратить несколько дней на разбиение на куски? Запихнуть процессы в прерывания? Да у меня под отладкой вообще прерывания глючат, все разобраться некогда. Тупик может не с автоматами, а в голове. Завтра выставка
--------------------
Уходя, оставьте свет...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|