|
Многозадачность на авр |
|
|
2 страниц
< 1 2
|
 |
Ответов
(15 - 25)
|
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 =)
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|