Hello all!
I am recently started using the TeensyThreads library in order to have two different tasks working concurrently. Everything was working fine until I started using dynamic memory allocation using malloc, new, String class, and others. So, the thing is, I know that the use of dynamic allocation is discouraged for MCUs, but in my full code (20k lines+) I am taking all precautions to avoid heap fragmentation and other issues.
The minimum working example that I could come up with showing the issues I am having is shown below. I am using Teensy 3.5 with PlatformIO Teensy 4.17.0 (but have also tested with Arduino IDE 1.8.19 and newest Teensyduino 1.57 and the issue is still reproducible for me).
When I run this code, the output on my serial monitor is:
So the problems I can see are:
Am I missing something big here? Can someone shed a light on this issue? I have tested with two different Teensy 3.5 boards and the results are the same. I have also tested with one Teensy 4.1 and the behavior of the malloc() changes. Now it works until the heap is full (as expected). However, I think this is merely because Teensy 4.1 uses a separate "RAM2" for dynamic memory allocation.
Thank you!
I am recently started using the TeensyThreads library in order to have two different tasks working concurrently. Everything was working fine until I started using dynamic memory allocation using malloc, new, String class, and others. So, the thing is, I know that the use of dynamic allocation is discouraged for MCUs, but in my full code (20k lines+) I am taking all precautions to avoid heap fragmentation and other issues.
The minimum working example that I could come up with showing the issues I am having is shown below. I am using Teensy 3.5 with PlatformIO Teensy 4.17.0 (but have also tested with Arduino IDE 1.8.19 and newest Teensyduino 1.57 and the issue is still reproducible for me).
Code:
#include <Arduino.h>
#include <TeensyThreads.h>
#define SIZE_ALLOC 500
uint32_t bytes_alloc = 0;
void thread_func()
{
while(1)
{
threads.delay(500);
char* pointer = (char*)malloc(SIZE_ALLOC);
if(pointer)
{
bytes_alloc += SIZE_ALLOC;
Serial.printf("Thread allocated %d bytes on the heap. Addr = %p . Total bytes allocated so far = %d\n", SIZE_ALLOC, pointer, bytes_alloc);
}
else
{
Serial.printf("Failed to allocate %d bytes on the heap!\n" , SIZE_ALLOC);
}
}
}
void setup()
{
Serial.begin(9600);
delay(5000);
threads.addThread(thread_func, 0, 8192); // The thread allocates around 5 kB on the heap and then malloc always returns NULL
//threads.addThread(thread_func); // The thread allocates just one time and than the functions stops
Serial.println(threads.threadsInfo()); // Information for thread 0 (main) is incorrect, information for thread 1 is missing
}
void loop()
{
// Do stuff
}
When I run this code, the output on my serial monitor is:
Code:
_____
0:Stack size:10240|Used:537067512|Remains:-537057272|State:RUNNING|
Thread allocated 500 bytes on the heap. Addr = 0x1fff3958 . Total bytes allocated so far = 500
Thread allocated 500 bytes on the heap. Addr = 0x1fff3b50 . Total bytes allocated so far = 1000
Thread allocated 500 bytes on the heap. Addr = 0x1fff3d48 . Total bytes allocated so far = 1500
Thread allocated 500 bytes on the heap. Addr = 0x1fff3f40 . Total bytes allocated so far = 2000
Thread allocated 500 bytes on the heap. Addr = 0x1fff4138 . Total bytes allocated so far = 2500
Thread allocated 500 bytes on the heap. Addr = 0x1fff4330 . Total bytes allocated so far = 3000
Thread allocated 500 bytes on the heap. Addr = 0x1fff4528 . Total bytes allocated so far = 3500
Thread allocated 500 bytes on the heap. Addr = 0x1fff4720 . Total bytes allocated so far = 4000
Thread allocated 500 bytes on the heap. Addr = 0x1fff4918 . Total bytes allocated so far = 4500
Thread allocated 500 bytes on the heap. Addr = 0x1fff4b10 . Total bytes allocated so far = 5000
Thread allocated 500 bytes on the heap. Addr = 0x1fff4d08 . Total bytes allocated so far = 5500
Failed to allocate 500 bytes on the heap!
Failed to allocate 500 bytes on the heap!
Failed to allocate 500 bytes on the heap!
So the problems I can see are:
- threads.threadsInfo() function is displaying incorrect stack bytes used/ remaining for thread 0 (main thread) and is not showing information for thread 1 (the one we created).
- The malloc() inside the thread function returns NULL after around 5.5kB have been allocated, despite having hundreds of kB left in the heap.
- If I change the line "threads.addThread(thread_func, 0, 8192);" to "threads.addThread(thread_func);", it seems like the thread_func function is executed only once and than it crashes. However state of the thread remains as RUNNING.
Am I missing something big here? Can someone shed a light on this issue? I have tested with two different Teensy 3.5 boards and the results are the same. I have also tested with one Teensy 4.1 and the behavior of the malloc() changes. Now it works until the heap is full (as expected). However, I think this is merely because Teensy 4.1 uses a separate "RAM2" for dynamic memory allocation.
Thank you!