Jump to content

    

Несколько вопросов начинающего

Если бы я знал «как надо» то не сидел бы тут… увы я знаю только как не надо. Сколько у меня было этих «плавающих» указателей, сколько геммора с потоками (не надо говорить, что все просто, одна инверсия приоритетов чего стоит. В итоге над основной идеей подумать времени мало.

Share this post


Link to post
Share on other sites

Кому они ключевые ? Да хоть new, хоть malloc - суть одна - любой залетевший дятел разрушит все. Посмотрите примеры программ на Java - там нет этого дебилизма. С++ позволит даже такое *(int *)0x40001234 = 0; На Яве вам никто не позволит пользоваться указателями, оных и нету, и никто не позволит приводить типы с уменьшением точности. С++ - это очень старый язык, он неплох для своих лет, но уже 2014 на дворе. Тот же ассемблер завуалированный.

Share this post


Link to post
Share on other sites
Помогите пожалуйста разобраться с 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 байт, а куча не используется.

 

Share this post


Link to post
Share on other sites
Более того ни кто не знает - нужно ли эту память зачищать?

Если на нее никто не ссылается - сборщик мусора освободит ее. Если среда выполнения поддерживает это. Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать. Отсюда все эти Unhandled exception - а в области MCU - просто hard fault (и то если это Кортекс итп, а обычно просто крик в форуме "виснет, помогите"

 

Share this post


Link to post
Share on other sites
ps если у вас сценарий, как в последнем моём примере, то зачем вам вообще динамика? пишите в статике, будет вам автоматическая зачистка
void myTask(void *context)

 

Видимо я плохо объяснил.

Речь не о памяти, занятой при выполнении задачи. Речь о стеке самой задачи. После удаления задачи память освобождается не сразу, а только в задаче idle . Если я сразу после удаления создаю новую задачу , а программа между этими двумя действиями не попадает в Idle task , то памяти может не хватить. Вопрос : как освободить память менее криво, чем вызывать между удалением и созданием vTaskDeleay ? Ну неужели не предусмотрено простого способа ?

Share this post


Link to post
Share on other sites
Видимо я плохо объяснил.

Речь не о памяти, занятой при выполнении задачи. Речь о стеке самой задачи. После удаления задачи память освобождается не сразу, а только в задаче idle . Если я сразу после удаления создаю новую задачу , а программа между этими двумя действиями не попадает в Idle task , то памяти может не хватить. Вопрос : как освободить память менее криво, чем вызывать между удалением и созданием vTaskDeleay? Ну неужели не предусмотрено простого способа ?

хороший вопрос. теоретически можно 100 раз создать задачу и 100 раз удалить, и при этом не разу не попав в idle.

 

Share this post


Link to post
Share on other sites
хороший вопрос. теоретически можно 100 раз создать задачу и 100 раз удалить, и при этом не разу не попав в idle.

Вы начали меня понимать !

 

Share this post


Link to post
Share on other sites
Кому они ключевые ? Да хоть new, хоть malloc - суть одна - любой залетевший дятел разрушит все. Посмотрите примеры программ на Java - там нет этого дебилизма. С++ позволит даже такое *(int *)0x40001234 = 0; На Яве вам никто не позволит пользоваться указателями, оных и нету, и никто не позволит приводить типы с уменьшением точности. С++ - это очень старый язык, он неплох для своих лет, но уже 2014 на дворе. Тот же ассемблер завуалированный.

Пользуйте BASIC и не будете так нервничать :)

 

Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать.

Вот к чему мир катится, программисты превращаются в кодеров, которым не надо будет думать :) и программы с миганием светодиодов для микроконтроллеров будут весить под несколько гигабайт :)

Share this post


Link to post
Share on other sites
Если на нее никто не ссылается - сборщик мусора освободит ее. Если среда выполнения поддерживает это. Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать. Отсюда все эти Unhandled exception - а в области MCU - просто hard fault (и то если это Кортекс итп, а обычно просто крик в форуме "виснет, помогите"

в мэтро может и не должен знать. а в реалтайм - не то что должен - ОБЯЗАН знать. Прогер должен занать, что вот в этом месте код исполняется 100 тактов, и что никакие сборщики мусора его не прервут.

 

так то это очередной вброс говна в вентилятор на тему c++ vs java. а ветка про FreeRTOS. Предлагаю дальнейшее обсуждение языков для мк перенести в более подходящее место и не засорять эту тему.

Share this post


Link to post
Share on other sites

Такой вопрос :

 

Система виснет, потому что какая-то задача берёт семафор, и не отдаёт.

Какие есть способы узнать, где именно семафор не отдан ?

Неужели никаких простых нет, и "всё плохо" ?

Share this post


Link to post
Share on other sites

ну у фриртоса вроде нет таких служебных функций. но так такое вроде на раз-два можно поймать.

заведи глобальную переменную 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(....);

 

 

Share this post


Link to post
Share on other sites

Тут был мой вопрос, ответ на который я сразу же сам нашёл :laughing:

Edited by ohmjke

Share this post


Link to post
Share on other sites

Всем доброго времени суток.

Есть такая проблема - если в кратце - то при пеердаче структуры в очереди теряются элементы.

Если по-конкретнне то есть вот такая структура:

    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МГц.

Почему так?

Edited by Halfback

Share this post


Link to post
Share on other sites

проблема оказалась в определении очереди (привет 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));
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this