|
|
  |
Несколько вопросов начинающего |
|
|
|
Jul 17 2014, 19:30
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ Jul 17 2014, 19:17)  Помогите пожалуйста разобраться с vPortFree. Вот допустим, я удаляю задачу. Что делать дальше ? Во первых вы должны понимать что такое динамическое выделение памяти и для чего оно нужно. как работает стек и куча. В 2-х словах не объяснить. Цитата Нужно передать в vPortFree в качестве параметра хендлер этой задачи ненужно. вы знаете как работают функции malloc() и free()? Для чего они нужны? Как работают операторы new и delete? Если знаете, то не должно возникнуть вопросов по vPortFree. vPortFree - работает аналогично. Если не знаете или плохо знаете, лучше не заморачивайтесь и работайте на стеке, т.е. без vPortFree pvPortMalloc, иначе выстрел в ногу гарантирован. Зачем вам динамическая память? Если нужны динамические задачи - делайте динамические задачи. Но зачем в динамических задачах использовать динамическую память? Цитата Можно ли перед этим, прямо внутри задачи, запустить vPortFree ? И как после этого задача продолжит работать , т.е. выполнит два последних действия v_Task_Handle=NULL; vTaskDelete(NULL); Ещё раз.... 1) выделяем в КУЧЕ 100 байт void *p = pvPortMalloc( 100 ); 2)создадим задачу и передаем в неё в качестве параметра указатель на выделенный блок памяти в куче. xTaskCreate( myTask, "Leningrad", 30, p, 5, NULL ); - создали задачу myTask, присвоили ей имя Leningrad, размер стека 30( байт или чего-то там, см доки, для стм32 вроде 30*4), приоритет задачи 5. Вот здесь выделяется для нужд задачи 120 байт (30*4) - это стек задачи. Это от дельная память от блока в 100 байт. 3)внутри задачи удаляем задачу vTaskDelete(). Задача остановиться и прекратит работать. Но 120 байт стека и 100 байт в куче не освободятся. 4)Происходит вызов idle. idle высвобождает 120 байт стека задачи. Но 100 байт выделеных с помощью pvPortMalloc ни кто не зачистит. Более того ни кто не знает - нужно ли эту память зачищать? может далее по алгоримту ваша программа будет работать так 5)создадим другую задачу и передадим в неё в качестве параметра указатель на выделенный блок памяти в куче. В этом блоке нужная информация xTaskCreate( yourTask, "Moskow", 50, p, 4, NULL ); и более того может быть 100 байт использоваться сразу в 10 задачах. одну задачу удалили- но остальные задачи пользуют эту память. Если у вас блок в 100 байт использует всего 1 задача и после удаления эти данные ненужны, то руками удалите pvPortFree(). Если удаляете внутри задачи, то перед vTaskDelete() Код //полезный код задачи использующий эти 100 байт pvPortFree(*vParam);//высвобождение памяти выделенной в куче, но не высвобождение памяти стека, т.е. 120 байт продлолжают использоваться //возможно ещё какойто полезный код, но здесь уже нельзя использовать эти 100 байт vTaskDelete(NULL); } ну вот как-то так. ps если у вас сценарий, как в последнем моём примере, то зачем вам вообще динамика? пишите в статике, будет вам автоматическая зачистка Код void myTask(void *context) { uint8_t array[100]; //выделение 100 байт на СТЕКЕ задачи //полезный код vTaskDelete(NULL); } //создаем задачу xTaskCreate( myTask, "Leningrad", 30 + 25, 0, 5, NULL );// создали задачу и выделили под стек на 100 байт больше При таком написании поле удаления задачи idle автоматически зачистит стек задачи? т.е. 120+100 байт, а куча не используется.
|
|
|
|
|
Jul 17 2014, 19:47
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(juvf @ Jul 17 2014, 23:30)  ps если у вас сценарий, как в последнем моём примере, то зачем вам вообще динамика? пишите в статике, будет вам автоматическая зачистка[code]void myTask(void *context) Видимо я плохо объяснил. Речь не о памяти, занятой при выполнении задачи. Речь о стеке самой задачи. После удаления задачи память освобождается не сразу, а только в задаче idle . Если я сразу после удаления создаю новую задачу , а программа между этими двумя действиями не попадает в Idle task , то памяти может не хватить. Вопрос : как освободить память менее криво, чем вызывать между удалением и созданием vTaskDeleay ? Ну неужели не предусмотрено простого способа ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jul 17 2014, 20:36
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(DASM @ Jul 17 2014, 23:26)  Кому они ключевые ? Да хоть new, хоть malloc - суть одна - любой залетевший дятел разрушит все. Посмотрите примеры программ на Java - там нет этого дебилизма. С++ позволит даже такое *(int *)0x40001234 = 0; На Яве вам никто не позволит пользоваться указателями, оных и нету, и никто не позволит приводить типы с уменьшением точности. С++ - это очень старый язык, он неплох для своих лет, но уже 2014 на дворе. Тот же ассемблер завуалированный. Пользуйте BASIC и не будете так нервничать  Цитата(DASM @ Jul 17 2014, 23:39)  Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать. Вот к чему мир катится, программисты превращаются в кодеров, которым не надо будет думать  и программы с миганием светодиодов для микроконтроллеров будут весить под несколько гигабайт
|
|
|
|
|
Aug 1 2014, 05:47
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
ну у фриртоса вроде нет таких служебных функций. но так такое вроде на раз-два можно поймать. заведи глобальную переменную const char* govnoPlace; и далее... Код xSemaphoreTake(....); govnoPlace = "void myFunk();"; //полезный код govnoPlace = 0; xSemaphoreGive(....); Код xSemaphoreTake(....); govnoPlace = "Место, где солнце ни когда не светит"; //полезный код govnoPlace = 0; xSemaphoreGive(....); потом проверяй чему равно govnoPlace, и поймешь в каком месте семафор застревает. Можно красивее сделать, перегрузить функции xSemaphoreTake и xSemaphoreGive и внутри них сделать присвоение к глобальному указателю приоритет текущей задачи, хандлер, имя задачи. А можно к присваивать к глобальной переменной имя файла и номер строки, где произошел захват. Если есть вывод, например в файл или в RS232, то можно сделать так Код xSemaphoreTake(....); printf(stream, "Take semafor from %s file, line %s", __FILE__, __LINE__); //полезный код printf(stream, "Give semafor from %s file, line %s", __FILE__, __LINE__); xSemaphoreGive(....);
|
|
|
|
|
Apr 23 2015, 05:21
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
Всем доброго времени суток. Есть такая проблема - если в кратце - то при пеердаче структуры в очереди теряются элементы. Если по-конкретнне то есть вот такая структура: Код typedef struct { unsigned short int LSensor_Num; unsigned short int WLevelValueAv; unsigned short int TimeStartMeasure; unsigned short int DurationMeasureSec; } WLevelData; Очередь инициализирована так: Код osMessageQDef(Level2Storage_Queue, 4, WLevelData); Level2Storage_QueueHandle = osMessageCreate(osMessageQ(Level2Storage_Queue), NULL); Задачи инициализированы так: Код osThreadDef(TX_Task, Start_TX_Task, osPriorityNormal, 0, 128); RD_TaskHandle = osThreadCreate(osThread(TX_Task), NULL);
osThreadDef(RX_Task, Start_RX_Task, osPriorityBelowNormal, 0, 128); Storage_TaskHandle = osThreadCreate(osThread(RX_Task), NULL); Есть задача где раз в 6 секунд происходит запись в очередь Код void Start_TX_Task(void const * argument) { portTickType xLastWakeTime; portBASE_TYPE xStatus; WLevelData WLevel = {1,111,0,60}; xLastWakeTime = xTaskGetTickCount(); /* Infinite loop */ for(;;) { xStatus = xQueueSendToBack(Level2Storage_QueueHandle,&WLevel,0); if(xStatus != pdPASS ) {} // Could not send to the queue vTaskDelayUntil(&xLastWakeTime,6000); } } Есть задача где периодически очередь считывается. Код void Start_RX_Task(void const * argument) { portBASE_TYPE xStatus; portTickType xLastWakeTime; WLevelData WLevel_rx; xLastWakeTime = xTaskGetTickCount();
for(;;) { if(uxQueueMessagesWaiting(Level2Storage_QueueHandle)) { xStatus=xQueueReceive(Level2Storage_QueueHandle,&WLevel_rx,0); } vTaskDelayUntil(&xLastWakeTime,130); } } И в итоге прием происходит, но последние 2 значения ( TimeStartMeasure и DurationMeasureSec) в структуре WLevel_rx всегда "0". Увеличивал кучу на 10кБ. Также увеличивал глубину стека в задачах. Приоритеты менял. Не помогло. МК: STM32F407VG, клок: 168МГц. Почему так?
Сообщение отредактировал Halfback - Apr 23 2015, 06:44
|
|
|
|
|
Apr 23 2015, 14:50
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
проблема оказалась в определении очереди (привет CubeMX) Код osMessageQDef(Level2Storage_Queue, 4, WLevelData); Level2Storage_QueueHandle = osMessageCreate(osMessageQ(Level2Storage_Queue), NULL); если заменить на классику Код RDLevel2Storage_QueueHandle = xQueueCreate(4,sizeof(WLevelData)); то структура передаётся без потерь. а проблема имхо кроется в Код #define osMessageQDef(name, queue_sz, type) \ const osMessageQDef_t os_messageQ_def_##name = \ { (queue_sz), sizeof (type) }
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id) { (void) thread_id; return xQueueCreate(queue_def->queue_sz, (uint32_t) sizeof(queue_def->item_sz)); }
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|