|
|
  |
Стэк в scmRTOS |
|
|
|
Apr 25 2012, 08:24
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(ViKo @ Apr 25 2012, 13:57)  Что это?  Мьютексы? Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм. Да, мутексы. Тут ведь дело не в ОС/не ОС. А в логике работы. Если две разные задачи должны одновременно работать с одним массивом, то это проблемы в логике. Вероятнее, нужно так: одна задача готовит данные в массиве, вторая - обрабатывает. При таком подходе мутекс вполне оправдан - он позволяет второй задаче подождать, пока первая задача подготовит данные. А в случае топикстартера всё похоже ещё проще - с массивом работает одна задача. Просто массив надо вынести из стека задачи. В этом случае можно и без мутекса.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 25 2012, 10:37
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(ViKo @ Apr 25 2012, 11:57)  Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм. Фактически дело обстоит так. Имеется очередь (OS::channel) из элементов структур (в структуре массив 250 байт + еще несколько переменных). Один процесс кладет в очередь данные (команды) когда нужно, другой процесс - извлекает их и обрабатывает. Очередь нужна, чтобы "копить" команды, т. к., команды могут выполняться достаточно долго, а терять их очень нежелательно. Ну и чтобы поместить элемент в очередь (push) и извлечь его оттуда (pop) приходится заводить временный элемент (тип и размер - выше), который и отжирает стек. Сама очередь - глобальная. Ну, может, архитектура не совсем нормальная... посоветуйте, пожалуйста, как лучше  Цитата(AHTOXA @ Apr 25 2012, 12:24)  А в случае топикстартера всё похоже ещё проще - с массивом работает одна задача. Просто массив надо вынести из стека задачи. В этом случае можно и без мутекса. Да, с массивом работает одна задача. Но их как минимум два  Принцип действия следующий. Процесс 1 (главный, дает команды): команда -> функция подготовки команды и помещения ее в очередь (помещает данные в свой локальный буфер 1, а из него в очередь) -> очередь. Процесс 2 (подчиненный выполняет команды): функция извлечения команды из очереди в буфер 2 и обработки команды. Команды занимают приличный объем и имеют разный размер. Буферы 1 и 2 - одного типа, под все команды (универсальные). Проблема в том как поместить в очередь команду, не используя для этого промежуточный буфер 1. Цитата(ReAl @ Apr 25 2012, 11:56)  Не надо так. Не только стеки, все внутренние структуры scmRTOS полетят во внешнюю память. Вообще всё. С соответствующим замедлением. Во внутренней останется только «стек main()», который и использовать-то толком тяжело. Вот так вот изначально было сделано... фактически во внутренних 8 кБ остался только стек main(). Кстати, возвращаясь к вопросу об устройстве стеков при использовании ОС. После старта ОС стек main() не используется (планировщик при передаче управления заносит в указатель стека адрес стека требуемого процесса, который может быть расположен где угодно)? А почему стек main() использовать тяжело? Цитата Спасибо, почитаем. Как я понял, надо осваивать скриптописание для линкера?  В двух словах, создаем специальные секции, в которые по необходимости переносим некоторые переменные, а эти секции линкуются куда надо (в данном случае во внешнюю память)? Цитата(AHTOXA @ Apr 25 2012, 11:44)  В scmRTOS 4.0 появился механизм для вычисления используемого каждым процессом стека (см. пример 4-Debug). Включите его, погоняйте. Узнаете, сколько чего и где. Может быть, всё спокойно влезет во внутреннее ОЗУ. Очень интересно  Цитата Почитайте про линкерные скрипты. Примеры используемых avr-gcc скриптов находятся в lib\ldscripts. Спасибо, почитаем, главное - понять что там написано  Пока линкерные скрипты для меня страшны
|
|
|
|
|
Apr 25 2012, 14:56
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(_Артём_ @ Apr 25 2012, 15:52)  Можно наверное в нём что-то расположить, используя указатели: адрес ведь известен. А, ну это да, можно... Цитата(AHTOXA @ Apr 25 2012, 16:59)  Дык, помещайте в очередь не сам буфер, а его номер  (Ну или как правильно сказал ViKo, указатель на него). Т. е., заводим большой массив (глобальный статический), который, к примеру, может вместить в себя 10 команд (размер данных каждой команды = размеру данных максимальной команды). Доступ к массиву между процессами разделяем с помощью мьютекса. Процесс 1 помещает команду в массив, указатель на команду в массиве помещает в очередь команд (она теперь маленькая по объему). Процесс 2 извлекает из очереди указатель на команду и по нему получает доступ к данным команды. Так? Но тогда придется как-то учитывать процессу 1, что в массиве по определенным адресам уже есть команды, чтобы не затереть ничего.
|
|
|
|
|
Apr 25 2012, 16:38
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (spongebob @ Apr 25 2012, 17:56)  Но тогда придется как-то учитывать процессу 1, что в массиве по определенным адресам уже есть команды, чтобы не затереть ничего. Вот тут на помощь и приходит куча. Процесс 1 запрашивает у менеджера кучи область памяти нужного размера (а не максимального), получает указатель, заполняет память по этому указателю, после чего помещает указатель в очередь и забывает про него. Процесс 2 достает указетель из очереди, обрабатывает данные и дает менеджеру кучи команду освободить память. Поскольку команды у вас обрабатываются строго по порядку - проблема фрагментации кучи не возникнет. Забота "о том, чтобы ничего не затереть" ложится на менеджер кучи. Выкладывал тут на форуме переделанный под scmRTOS (завернутый в мутекс и переложенный на C++) легковесный менеджер кучи имени zltigo. Кстати, при словах "Команды занимают приличный объем и имеют разный размер" приходят на ум умные слова "полиморфизм" и "кормление слона в примере 3-channel". Т.е. все команды можно сделать потомками одного абстрактного класса с виртуальной функцией execute(), которую и будет вызывать по извлеченному из канала указателю Процесс 2. И тогда команды очень легко и красиво создаются при помощи оператора new() и забирают из кучи ровно столько памяти, сколько необходимо. И заботу о необходимом каждой конкретной команде объеме памяти полностью берет на себя компилятор. А освобождается память после выполнения execute() оператором delete(). И при таком подходе компилятор же будет следить за тем, чтобы вы не забыли написать обработку для какой-либо команды.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 26 2012, 05:12
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(Сергей Борщ @ Apr 25 2012, 20:38)  Вот тут на помощь и приходит куча. Процесс 1 запрашивает у менеджера кучи область памяти нужного размера (а не максимального), получает указатель, заполняет память по этому указателю, после чего помещает указатель в очередь и забывает про него. Процесс 2 достает указетель из очереди, обрабатывает данные и дает менеджеру кучи команду освободить память. Поскольку команды у вас обрабатываются строго по порядку - проблема фрагментации кучи не возникнет. Забота "о том, чтобы ничего не затереть" ложится на менеджер кучи. Выкладывал тут на форуме переделанный под scmRTOS (завернутый в мутекс и переложенный на C++) легковесный менеджер кучи имени zltigo. Кстати, при словах "Команды занимают приличный объем и имеют разный размер" приходят на ум умные слова "полиморфизм" и "кормление слона в примере 3-channel". Т.е. все команды можно сделать потомками одного абстрактного класса с виртуальной функцией execute(), которую и будет вызывать по извлеченному из канала указателю Процесс 2. И тогда команды очень легко и красиво создаются при помощи оператора new() и забирают из кучи ровно столько памяти, сколько необходимо. И заботу о необходимом каждой конкретной команде объеме памяти полностью берет на себя компилятор. А освобождается память после выполнения execute() оператором delete(). И при таком подходе компилятор же будет следить за тем, чтобы вы не забыли написать обработку для какой-либо команды. Принцип понятен, спасибо большое за рекомендации. Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно? Кстати, в WinAVR уже есть менеджер кучи и чем он отличается от выше Вами указанного?
|
|
|
|
|
Apr 26 2012, 07:16
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

|
Цитата(spongebob @ Apr 26 2012, 08:12)  Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно? Опять мифы!!! Аналогичные мифы (применительно к МК) о C++, printf/scanf, RTOS и прочая циркулируют в эмбеддерской среде с пугающей живучестью. Подумайте над следующим. Чьи ресурсы занимаются? Контроллера или лично Ваши (рабочее время, деньги)? Ваши затраты будут единоразовыми и неизвестно в каком случае больше - применив кучу или изголяясь окольными путями. В случае контроллера, если он решает поставленную задачу и решает успешно, то какая Вам разница? Попробуйте лично и определитесь. PS Когда не устраивает библиотечный вариант какой-либо фичи, напишите или используйте кем-нибудь написанный готовый - облегчённый. Что касается варианта кучи, то Вам уже предложили или возьмите из второй версии scmRTOS.
|
|
|
|
|
Apr 26 2012, 07:28
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (spongebob @ Apr 26 2012, 08:12)  Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно? А вы попробуйте. На первый взгляд ресурсоемким и невыгодным выглядит решение без менеджера кучи. Менеджеры бывают разные... В вашем случае менеджер можно упростить до предела, сделав его на базе кольцевого буфера. Выделение памяти двигает указатель головы, освобождение - указатель хвоста. Вы обещаете освобождать память строго в том же порядке, в котором она была выделена (а в случае вашей очереди это так и получается) и за счет этого менеджеру не нужны поиск свободного блока нужного размера, "склеивание" освобожденных блоков и т.д. А чтобы оставить возможность в дальнейшем для каких-то других целей использовать "настоящий" менеджер - можно обращаться к этому через переопределенный оператор new. QUOTE (spongebob @ Apr 26 2012, 08:12)  Кстати, в WinAVR уже есть менеджер кучи и чем он отличается от выше Вами указанного? Не знаю. Я этот менеджер использовал на ARM, где родной библиотечный тянет за собой мама дорогая сколько лишнего. Менеджер из avr-libc я не использовал. Сравните, будет интересно узнать результаты.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 26 2012, 09:04
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Сергей Борщ @ Apr 26 2012, 10:28)  В вашем случае менеджер можно упростить до предела, сделав его на базе кольцевого буфера. Выделение памяти двигает указатель головы, освобождение - указатель хвоста. Вы обещаете освобождать память строго в том же порядке, в котором она была выделена (а в случае вашей очереди это так и получается)... Вряд ли такую строго упорядоченную конструкцию можно назвать кучей. Скорее уж, действительно, кольцевой буфер. Тогда к чему лишние процедуры выделения, освобождения...? Я понимаю, работа с этими массивами идет постоянно. Вот и сделать их глобальными. Иметь некий индекс текущего рабочего буфера, им и манипулировать.
|
|
|
|
|
Apr 27 2012, 06:25
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(Сергей Борщ @ Apr 27 2012, 01:06)  Кучу - нет. По стеку можно посмотреть его исходники, порядка 20-30 байт плюс на передачу параметров (это относится только к sprintf из avr-libc, естественно). Ну, получается и не прожорливый совсем... мельком погуглил - жалуются на прожорливость. Да, вопрос про avr-libc  Кстати, в WinAVR есть эти исходники (сейчас нет под рукой посмотреть, к сожалению)? Наверное, в avr-libc sprintf жутко оптимизированный под AVRы?
|
|
|
|
|
Apr 27 2012, 10:01
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (spongebob @ Apr 27 2012, 09:25)  Кстати, в WinAVR есть эти исходники (сейчас нет под рукой посмотреть, к сожалению)? В WinAVR нет. Лежат отдельно в репозитории avr-libc. QUOTE (spongebob @ Apr 27 2012, 09:25)  Наверное, в avr-libc sprintf жутко оптимизированный под AVRы?  Да.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|