Artkop 0 30 июля, 2010 Опубликовано 30 июля, 2010 · Жалоба Всем привет! Использую операционку Keil RL-RTX. Определено две задачи, имеющие одинаковый приоритет и выполняющиеся параллельно: //---------------------------------------------------------------------------------------------------- /*! \brief Задача RTX для работы с радиомодемом 1, подключенным к порту uart 0 */ //---------------------------------------------------------------------------------------------------- __task void modem1(void) { while(1) { RadiomModemSubsystem(RADIO_MODEM_1); } } //---------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------- /*! \brief Задача RTX для работы с радиомодемом 2, подключенным к порту uart 2*/ //---------------------------------------------------------------------------------------------------- __task void modem2(void) { while(1) { RadiomModemSubsystem(RADIO_MODEM_2); } } //---------------------------------------------------------------------------------------------------- Как видно, задачи вызывают одну и туже функцию. Создается ли для каждой задачи свой экземпляр функции со своими локальными переменными? Вот эта функция: static unsigned char Modem1Buffer[bUF_MAX_SIZE] = {0x00}; static unsigned char Modem2Buffer[bUF_MAX_SIZE] = {0x00}; void RadiomModemSubsystem(unsigned char numModem) { unsigned char queue = UNKNOWN_QUEUE; unsigned char *dataBuf = 0; switch(numModem) { case RADIO_MODEM_1: queue = MODEM_1_QUEUE; dataBuf = &Modem1Buffer[0]; break; case RADIO_MODEM_2: queue = MODEM_2_QUEUE; dataBuf = &Modem2Buffer[0]; break; default: return; } // здесь управление и обмен с модемом } Интересует, что будет с переменными queue и *dataBuf. Задача modem 1 вызывает функцию RadiomModemSubsystem с параметром RADIO_MODEM_1. Для локальных переменных queue и *dataBuf выделяется память, идет выполнение. Задача modem 1 израсходовала свой квант времени и теперь выполняется задача modem 2. Задача modem 2 вызывает функцию RadiomModemSubsystem с параметром RADIO_MODEM_2 и для локальных переменных queue и *dataBuf выделяется новая память (то есть, это экземпляр функции для другой задачи), правильно? Не будет ситуации, что адреса локальных переменных совпадут, и мы перепишем буфер dataBuf и номера очереди queue другой задачи. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Quasar 20 30 июля, 2010 Опубликовано 30 июля, 2010 · Жалоба Создается ли для каждой задачи свой экземпляр функции со своими локальными переменными? Функция остается в одном экземпляре :). Просто кусок кода во флешь. А локальные переменные в ней находятся в своем потоке (в стеке конкретной задачи). При переключении контекста двух этих задач они будут иметь значения текущей задачи и их значения ни как не связаны со значениями параллельно выполняемых задач. А вот если их сделать static то тогда, они начнут вести себя как глобальные переменные в плане много поточности. А функция RadiomModemSubsystem написана странно, почему нельзя сразу передавать ей queue и dataBuf? Нафига этот switch нужен? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Artkop 0 30 июля, 2010 Опубликовано 30 июля, 2010 (изменено) · Жалоба То есть, локальная переменная функции становится локальной переменной задачи? Тогда если сделать локальный буфер внутри функции на много байт и вызвать ее из задачи, такая функция вполне может привести к переполнению стека! (В RL-RTX он по умолчанию 64 байта.) А функция RadiomModemSubsystem принимает на вход только номер модема, т.к. переменная queue - это номер очередь FIFO для пакетов радиомодема, и в месте вызова (в main) про подсистему обработки очередей ничего не известно. Для main она скрыта. (h файл соответствующий я не подключаю, там и так дофига всего подключено, сложно разобраться потом). Вот как это выглядит: void RadiomModemSubsystem(unsigned char numModem) { unsigned char queue = UNKNOWN_QUEUE; unsigned char *dataBuf = 0; switch(numModem) { case RADIO_MODEM_1: queue = MODEM_1_QUEUE; dataBuf = &Modem1Buffer[0]; break; case RADIO_MODEM_2: queue = MODEM_2_QUEUE; dataBuf = &Modem2Buffer[0]; break; default: return; } if (QueueIsEmpty(queue) == QUEUE_NOT_EMPTY) // если в очереди есть данные на отправку по радиомодему { FreeString(&dataBuf[0], BUF_MAX_SIZE); // очищаем буфер SetRadioModemToCtrlMode(numModem); SendCmdToRadioModem(RM_REQUEST_STATUS, &dataBuf[0], numModem); // отправляем команду ReceivePacketFromRadioModem(&dataBuf[0], numModem); // получаем статус модема // обрабатываем статус .. // .. SetRadioModemToDataMode(numModem); RetrieveDataFromQueue(&dataBuf[0], &sizeOfData, queue); // извлекаем пакет из очереди // оправляем пакет ... } } А буфер радиомодема dataBuf можно и так сделать: __task void modem2(void) { unsigned char Modem2Buffer[bUF_MAX_SIZE] = {0x00}; while(1) { RadiomModemSubsystem(RADIO_MODEM_2, &Modem2Buffer[0]); } } но тогда задачу нужно инициализировать с помощью ф-ии os_tsk_create_user (делать ей стек большой отдельно). В этом нет необходимости. Изменено 30 июля, 2010 пользователем Artkop Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
evg123 0 3 августа, 2010 Опубликовано 3 августа, 2010 · Жалоба Вы можете в отладчике увидеть, как у вас там организуются разные переменные. Установить точки прерывания на вызове функции в разных задачах, и посмотреть как они отрабатывают. Кстати ulink позволяет устанавивать прерывания на лету. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Artkop 0 3 августа, 2010 Опубликовано 3 августа, 2010 (изменено) · Жалоба Да, я ulink2 пользуюсь. Могу поставить 2 точки останова для двух задач RTX и у переменной queue видимо будут два разных адреса? Завтра на работе проверю. Спасибо за идею! Изменено 3 августа, 2010 пользователем Artkop Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Artkop 0 4 августа, 2010 Опубликовано 4 августа, 2010 (изменено) · Жалоба Локальные переменные функции располагаются в регистрах общего назначения контроллера и при смене задачи сохраняются в область стека Register Context Storage. Соответственно при продолжении выполнения задачи этот контекст восстанавливается. Видимо как то так. Изменено 4 августа, 2010 пользователем Artkop Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Shein 0 5 февраля, 2011 Опубликовано 5 февраля, 2011 (изменено) · Жалоба Коллеги, кто-нибудь может подсказать, какие требования к размерам глобальніх стеков у RTX-kernel? В доке сказано: The other stack spaces need to be configured from the ARM startup file. All tasks run in user mode. The task scheduler switches the user/system mode stack between tasks. For this reason, the default user/system mode stack (which is defined in the startup file) is used until the first task is created and started. The default stack requirements are very small, so it is optimal to set the user/system stack in the startup file to 64 bytes. т.е. получается что для нее достаточно задать минимум объема стека для user/system режимов и все? Нужно ли задавать стек для режима Supervisor и сколько? Я так понимаю что нужно, т.к.она же пользуются swi. Но явного указания на это и сколько я в доках не нашел. Остальные (IRQ/FIQ) нужно задавать соответственно при использовании моих обработыиков, для RTX они не нужны, так? Доавлено: Вопрос снят, надо внимательно читать доки :) Minimum stack sizes for RTX kernel configured in STARTUP.S are: Supervisor Mode 32 bytes (0x00000020) Interrupt Mode 64 bytes (0x00000040) User Mode 80 bytes (0x00000050) Изменено 5 февраля, 2011 пользователем Shein Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться