|
Многозадачность на авр |
|
|
|
Sep 5 2010, 14:37
|
Местный
  
Группа: Свой
Сообщений: 443
Регистрация: 22-07-06
Из: Украина, г. Харьков
Пользователь №: 19 006

|
Цитата(Dimmix @ Sep 5 2010, 15:06)  Подскажите однако как лучше запустить многозадачность на авр-ах Все зависит от задачи. Если не нужно задачи динамически создавать/удалять, то, ИМХО, scmRTOS - лучший выбор. Доку от нее в любом случае почитать стоит.
|
|
|
|
|
Sep 6 2010, 21:49
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(Dimmix @ Sep 5 2010, 16:06)  Подскажите однако как лучше запустить многозадачность на авр-ах Ничего сложного. Можно взять scmRTOS или freeRTOS, можно самому написать в расслабленном режиме за неделю. Всего-то нужно уметь сохранять и восстанавливать контекст (за вдохновением см. реализацию setjmp и longjmp из avr-libc), ну и при запуске задачи придется вручную расписать нужную область памяти так, как это сделала бы функция save_context. Ну. и потом просто восстановиться туда - все, мы уже летаем. На самом деле, занятие это достаточно грустное - скажем, в mega168 с её килобайтом памяти влезают всего две-три задачи, так что для таких развлечений лучше подобрать кристалл, где памяти хотя-бы два-четыре килобайта минимум.
|
|
|
|
|
Sep 7 2010, 03:19
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата ...нужно уметь сохранять и восстанавливать контекст... Самое простое, ИМХО, это посмотреть реализацию TinyTimber. Вообще-то Dimmix спросил Цитата как лучше . Я предпочитаю кооператив а-ля Protothreads - как на AVR, так и на других МК. Считаю, что в большинстве случаев (кроме узкозаточенных решений) критичная ко времени реагирования часть кода должна быть минимизирована и умещаться в обработчиках прерываний, а остальное спокойно работать в фоне. Расход памяти при кооперативе значительно меньше, но приходится платить рулением статическими переменными и решать несколько больше вопросов синхронизации.
--------------------
aka Vit
|
|
|
|
|
Sep 7 2010, 14:34
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(MrYuran @ Sep 7 2010, 12:49)  Кроме вытесняющей, бывает ещё и кооперативная многозадачность, которая дополнительной памяти практически не требует. Это как? Что там, что там - сколько задач, столько и контекстов, стеков и struct task'ов. Цитата(777777 @ Sep 7 2010, 12:19)  А как ее можно не запускать? Вряд ли хоть один проект может обойтись без прерываний, а обычно 90% работы выполняется в них. А что это, если не многозадачность? Это не многозадачность, это асинхронная стейт-машина :-) Цитата(sensor_ua @ Sep 7 2010, 07:19)  Я предпочитаю кооператив а-ля Protothreads - как на AVR, так и на других МК. Кооперативность или вытесняемость - вещь, в общем-то перпендикулярная к методу организации передачи управления. Цитата Считаю, что в большинстве случаев (кроме узкозаточенных решений) критичная ко времени реагирования часть кода должна быть минимизирована и умещаться в обработчиках прерываний, а остальное спокойно работать в фоне. Расход памяти при кооперативе значительно меньше, но приходится платить рулением статическими переменными и решать несколько больше вопросов синхронизации. Все это так, но прототреды и прочие завуалированные стейт-машины дико неудобны тем, что _весь_ код должен поддерживать асинхронность сверху донизу. В какой-то момент придется выбирать: либо память и честное переключение контекста, либо повеситься без мыла на прерываниях.
|
|
|
|
|
Sep 7 2010, 14:42
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(slanted @ Sep 7 2010, 18:34)  Это как? Что там, что там - сколько задач, столько и контекстов, стеков и struct task'ов. Кооперативность или вытесняемость - вещь, в общем-то перпендикулярная к методу организации передачи управления. А вот и нет. В кооперативной задача сама "знает", когда отдаст управление, и соответственно сохраняет свой контекст. Не все регистры подряд, а только нужную инфу. Например, в static переменных. В отличие от вытесняющей, где ход выполнения задачи может прерваться вообще посреди оператора или функции.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Sep 7 2010, 15:26
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(MrYuran @ Sep 7 2010, 18:42)  А вот и нет. В кооперативной задача сама "знает", когда отдаст управление, и соответственно сохраняет свой контекст. Не все регистры подряд, а только нужную инфу. Например, в static переменных. Те регистры что не "все подряд" сохранит компилятор при вызове функции переключения задач ;-) А то что вы описываете - это прототреды.
|
|
|
|
|
Sep 7 2010, 16:19
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Все это так, но прототреды и прочие завуалированные стейт-машины дико неудобны тем, что _весь_ код должен поддерживать асинхронность сверху донизу. В какой-то момент придется выбирать: либо память и честное переключение контекста, либо повеситься без мыла на прерываниях. Похоже, у Вас просто нет опыта использования подобных технологий. Холивар разводить не хочу, да и пока не о чем спорить. Потому как вижу только Ваши эмоции, но ничего относящегося к предмету.
--------------------
aka Vit
|
|
|
|
|
Sep 7 2010, 16:41
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(sensor_ua @ Sep 7 2010, 20:19)  Похоже, у Вас просто нет опыта использования подобных технологий. Холивар разводить не хочу, да и пока не о чем спорить. Потому как вижу только Ваши эмоции, но ничего относящегося к предмету. Покажите код штоле ;-)
|
|
|
|
|
Sep 7 2010, 20:49
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Покажите код штоле ;-) Вот выдрал простой кусочек из реального старинного проекта "выходного дня" - всего-лишь блинк, который пришлось вставлять в программку вместо обычного ожидающего Код void BlinkLed(unsigned short Blink_Count, unsigned short LED_on_ms, unsigned short LED_off_ms) дабы добавить к имевшейся задаче ещё парочку параллельно выполняющихся. Всё это фунциклирует  без жесткого риалтайма. Код unsigned short clock(void){ unsigned short tms; __enter_critical(); tms = xtimer_ms; __exit_critical(); return (tms);
}
unsigned short clock_Elapsed(unsigned short tstart){ return ((unsigned short)( clock() - tstart)); }
static unsigned short BCount; static unsigned short Bon_ms; static unsigned short Boff_ms; static unsigned short Bts_ms;
void xBlinkLed_Start(unsigned short Blink_Count, unsigned short LED_on_ms, unsigned short LED_off_ms){ BCount = Blink_Count; Bon_ms = LED_on_ms; Boff_ms = LED_off_ms; Bts_ms = clock(); LED_OFF(); }
bool xBlinkLed_Done(bool forceoff){ static unsigned char st = 0; if(forceoff){ BCount = 0; st = 0; LED_OFF(); } if(BCount){ switch(st){ case 0: if(clock_Elapsed(Bts_ms) < Boff_ms)break; LED_ON(); Bts_ms = clock(); st = 1;
case 1: if(clock_Elapsed(Bts_ms) < Bon_ms)break; LED_OFF(); Bts_ms = clock(); BCount -= 1; st = 0; break;
default: st = 0; break; } } if(BCount == 0){ return true;} return false; } Тут в явном виде хоть и не представлены именно прототриды, но зато неплохо выражены способы применения и видны накладные
--------------------
aka Vit
|
|
|
|
|
Sep 8 2010, 11:40
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(sensor_ua @ Sep 8 2010, 00:49)  Вот выдрал простой кусочек из реального старинного проекта "выходного дня" - всего-лишь блинк, который пришлось вставлять в программку вместо обычного ожидающего Жуть :-) На тредах это было бы просто Код while ( timeout--) { timeout & 1 ? LED_ON() : LED_OFF(); kernel_sleep(delay); } Но речь не столько об этом, сколько о том, что написание и отладка более-менее сложной логики превращается в ад - представьте что у вас там пара десятков состояний, причем переключаемых не по "switch ( g_state )", а по битовым флажкам, условиям нулевости некоторых указателей и так далее. Нет, адекватно перенумеровать их все можно далеко не всегда, да и что толку с того, что если мне надо будет постоянно помнить, что в state1 у меня p_queue должен быть NULL, а в state2 взведен флаг F_NEW_MESSAGE и сброшен F_RESYNC - не проще ли сразу их и проверять? Это раз. Второе, даже если я успешно построил свою машину с двумя десятками состояний, я не смогу написать код в виде: Код void serial_console_thread(void) { for(;;) { print("What's your name?"); readline(buf); print("Hello, "); print(buf); }
void gui_thread(void) { for(;;) { key = readkey(); if ( key == KEY_RIGHT ) menu_move_right(); .... else beep(); // wrong key pressed display_update(); } } как это позволила бы сделать система с передачей управления через сохранение контекста (неважно, с вытеснением или без оного - я же могу просто в ключевых местах yield() расставить). Я буду вынужден _весь_ код, с самого нижнего до самого верхнего уровня порезать кровавыми ножницами на мелкие кусочки в асинхронном стиле и переключать их по тем же флагам, т.е. что-то вроде: Код while ( (msg=get_message())!=0 ) { switch ( msg ) { case SERIAL_TX_COMPLETE: case SERIAL_RX_COMPLETE: console_update(&console, msg); break; case DISPLAY_UPDATE_COMPLETE: ... break; case KEY_PRESSED: ... break; } }
void console_update(struct console *pc, int msg) { switch ( pc->state ) { case START: serial_send_async("What's your name?"); pc->state = QUESTION_SENT; break; case QUESTION_SENT: switch ( msg ) { case SERIAL_TX_COMPLETE: serial_receive_async(buf); break; case SERIAL_RX_COMPLETE: pc->state = GREETING_SENT; struct vector v[] = { "Hello, ", buf, "!"}; serial_send_async_vector(v, 3); break; } break; case GREETING_SENT: if ( msg == SERIAL_TX_COMPLETE ) pc->state = START; break; } } Теперь попробуйте вообразить в таком стиле не "Hello, Vasya!", а что-то вроде SMTP, или, скажем, веб-панель управления... а светодиодами помигать - это не показатель.
|
|
|
|
|
Sep 8 2010, 11:50
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(slanted @ Sep 8 2010, 15:40)  Я буду вынужден _весь_ код, с самого нижнего до самого верхнего уровня порезать кровавыми ножницами на мелкие кусочки в асинхронном стиле и переключать их по тем же флагам Да, есть такое... Но тут, как говорится, за всё надо платить. И за удобство, и за свободные ресурсы. Сомневаюсь я что-то, что кому-нибудь придёт в голову поднимать SMTP или WEB на меге с 1к ОЗУ
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Sep 8 2010, 12:15
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата я же могу просто в ключевых местах yield() расставить Вот тут и начинается "кровосмешение" - у мну в коде именно yield() и ставится. Примерно так Код void serial_console_thread(void) { __TICK_BEGIN__ while( !print("What's your name?"){ TICK_YIELD(); } readline(buf); while(!buf){ TICK_YIELD(); readline(buf); } while( !print("Hello, "){ TICK_YIELD(); } while( !print(buf){ TICK_YIELD(); } __TICK_END__ } void gui_thread(void) { __TICK_BEGIN__ while( NO_KEY == key = readkey() ){ TICK_YIELD();} if ( key == KEY_RIGHT ) menu_move_right(); .... else beep(); // wrong key pressed display_update(); __TICK_END__ } Метки в TICK_YIELD() создаются из макроса __LINE__. Но где надо я могу себе позволить тупо перерисовать из документации машину состояний с теми же именами состояний (например машина состояний ModBus).
--------------------
aka Vit
|
|
|
|
|
Sep 8 2010, 14:20
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(sensor_ua @ Sep 8 2010, 16:15)  Вот тут и начинается "кровосмешение" - у мну в коде именно yield() и ставится. Примерно так Если это реализация на основе duff's device, то вы не сможете сделать yield изнутри функции. В результате stdio отдыхает, библиотеки, если они не специально спроектированы под async, отдыхают...
|
|
|
|
|
Sep 8 2010, 15:07
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата вы не сможете сделать yield изнутри функции Простите, я неясно написал? TICK_YIELD() это реализация yield(). Вываливаемся в шедулер или вызывающую функцию - если второе, то организация вываливания в шедулер просто чуть-чуть дольше, чем в первом случае. Как ни странно, но последовательный набор действий с ожиданиями (ввод-вывод разной природы) используется довольно часто и второй случай без срочного вываливания в шедулер вполне востребован. Насчёт stdio частично правы - одним ретаргетингом ожидающий ввод-вывод на неожидающий не поправишь, но как и с библиотеками проблема полноценного использования stdio более теоретического плана, чем практического. Асинхронный ввод-вывод же (да, его нужно делать самому - в ANSI он не есть таковой) организовывается как неожидающий и при этом легко превращается в ожидающий, но не наоборот. Оборачивание же стандартных sprintf и sscanf вполне несложная работенка.
--------------------
aka Vit
|
|
|
|
|
Sep 8 2010, 15:52
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(sensor_ua @ Sep 8 2010, 19:07)  Простите, я неясно написал? TICK_YIELD() это реализация yield(). Вываливаемся в шедулер или вызывающую функцию - если второе, то организация вываливания в шедулер просто чуть-чуть дольше, чем в первом случае. Насколько дольше? Как по мне - придется в каждую функцию во всей цепочке вызовов вставить индикатор, показывающий, просто так мы возвращаемся или с отдачей управления. Цитата Как ни странно, но последовательный набор действий с ожиданиями (ввод-вывод разной природы) используется довольно часто и второй случай без срочного вываливания в шедулер вполне востребован. Для ввода-вывода с некоторой минимальной обработкой это вполне применимо, кто бы спорил. Вот сложная логика, вкупе с отсутствием локальных переменных - лучше ну его нафиг. Повторюсь - подобные подходы плохи не тем, что они "усложняют" код, они плохи тем, что требуют асинхронности по _всему_ коду, снизу доверху.
|
|
|
|
|
Sep 8 2010, 18:04
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Насколько дольше? Как по мне - придется в каждую функцию во всей цепочке вызовов вставить индикатор, показывающий, просто так мы возвращаемся или с отдачей управления.  Булевый код возврата (или NULL/!NULL) практически ничего не стОит. А анализ кода возврата при небольшой вложенности вполне сравним по времени с сохранением/загрузкой контекста (тут нужно цифры рассматривать, но, ИМХО, при глубине вложенности до 3 чаще вытеснение проиграет, а если глубина больше 4, то это уже скорее будет говнокод  ). Цитата Вот сложная логика, вкупе с отсутствием локальных переменных - лучше ну его нафиг. Ну не знаю - мне удобно для всякой логики (может то, что Вы называете сложной, не попадалось) - важно только понимать, где могут быть ощутимо долгоиграющие участки кода и там отдавать управление вручную. Последнее скорее может показаться непривычно (я бы сказал, что оно просто несколько не похоже на примеры из учебников), чем неудобно. Цитата они плохи тем, что требуют асинхронности по _всему_ коду, снизу доверху опять  Имею другое мнение. Считаю, что оперирование асинхронно изменяющимися данных и наличие буферов для них есть само по себе основным источником асинхронности в системах на МК. А если семь бед - один ресет(С), то зачем быть святее Папы Римского?
--------------------
aka Vit
|
|
|
|
|
Sep 8 2010, 21:13
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 2-01-08
Пользователь №: 33 768

|
Цитата(sensor_ua @ Sep 8 2010, 22:04)   Булевый код возврата (или NULL/!NULL) практически ничего не стОит. А анализ кода возврата при небольшой вложенности вполне сравним по времени с сохранением/загрузкой контекста (тут нужно цифры рассматривать, но, ИМХО, при глубине вложенности до 3 чаще вытеснение проиграет, а если глубина больше 4, то это уже скорее будет говнокод  ). Это процессору он ничего не стоит. А вот возвращать осмысленный результат придется через глобальное состояние - код возврата-то уже занят. Конечно, все можно завернуть в макросы, но в один прекрасный момент мы обнаружим, что пишем не на C, а черт-те на чём :-) Цитата(sensor_ua @ Sep 8 2010, 22:04)  Считаю, что оперирование асинхронно изменяющимися данных и наличие буферов для них есть само по себе основным источником асинхронности в системах на МК. А если семь бед - один ресет(С), то зачем быть святее Папы Римского? Если уж на то пошло, то весь мир вокруг асинхронный ;-) И, опять же, если абстрагироваться по максимуму - само наличие разницы между синхронным и асинхронным кодом есть следствие линейной модели стека и отсутствия поддержки coroutines. Такшта спор о том, какие костыли неудобнее :-) Хотя и практически важный в некоторых частных случаях :-)
|
|
|
|
|
Sep 9 2010, 05:19
|

山伏
    
Группа: Свой
Сообщений: 1 827
Регистрация: 3-08-06
Из: Kyyiv
Пользователь №: 19 294

|
Цитата(Dimmix @ Sep 5 2010, 15:06)  Подскажите однако как лучше запустить многозадачность на авр-ах Contiki... Цитата(MrYuran @ Sep 8 2010, 14:50)  Сомневаюсь я что-то, что кому-нибудь придёт в голову поднимать SMTP или WEB на меге с 1к ОЗУ Верно... но 4-х уже с головой. Пишу это скорее как прикол. Сам никогда не использовал эту чудо-ось, если есть у кого реальный опыт - рассказывайте. Цитата Веб-браузер (возможно самый маленький в мире) ... даже такое там есть... P.S.: Гы... Сервак на 64k. - CPU: MOS-Technology 8bit 6510 - Clock Speed: 1Mhz.  Однако... Зажрались мы. Может Хейц и прав был чо 512 k RAM должно хватать всем?
--------------------
Нас помнят пока мы мешаем другим... //-------------------------------------------------------- Хороший блатной - мертвый... //-------------------------------------------------------- Нет старик, это те дроиды которых я ищу...
|
|
|
|
|
Sep 9 2010, 14:49
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Dimmix @ Sep 9 2010, 18:00)  т.е. Вы утверждаете что лучше поставить на атмегу ось и мышь Ось и мышь - понятия абсолютно перпендикулярные, никак друг от друга не зависят Равно как USB, Ethernet и прочее другое. Вам просто привели в пример разные подходы. Самый простой - каруселька из стэйт-машин. Простой поначалу, до определённого уровня сложности проекта. С определённого этапа проще становится встроенная ось. Так что, всё зависит от задачи.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|