Teensy 3.x multithreading library first release

Dont know if this also helps, but the time slices of each thread can be changed which affects how long task switching stays in that thread, i had to adjust my time slices when i ran multiple uart displays in previous project to stop jittering
 
Fernando, thanks for making this. It certainly makes for better looking multitasking code. My simple test runs fine on teensy 4.0.
 
Any thoughts on setting a very large time slice to do cooperative multi-tasking with TeensyThreads?

I needed yield-based cooperative multitasking that works on both Teensy 3 and Teensy 4, and so far this seems to work well. Thanks for the fine work!

Maybe this could be turned into a feature, and avoid the 1000th-hour overflow-of-doom...
 
I try to develop programs with threads and i have one problem. My program have few threads and one is stuck sometimes. To debug I have asked to one running thread to send me the thread state of the dysfunctional thread. Before the crash, I obtain 1 (running) for the state, but when it crash, I obtain great value 1628405760.Is there anybody who knows the signification of this value ?
Regards
 
Just to add more details to my problem, Suspend and restart dysfunctional thread seem reload it correctly and Now state is 1. I don't have found my crash source, but I can place one state control mechanism (like watch dog) in another thread and suspend-restart the dysfunctional thread. I know it's not very "professional, " but for me, it's a bit complex to debug with just printing a message. All suggestions to debug threads will be welcome.
 
maybe try posting your code? are you using mutexes to protect variables or peripherals shared between threads?
 
maybe try posting your code? are you using mutexes to protect variables or peripherals shared between threads?

Sorry Tonton but my code is a bit complexe and need lot of external libraries that why i can't send it. I have identified than the bug (crashing thread) is arround access asynchronusly to one FIFO (using this librairy https://github.com/rlogiacco/CircularBuffer ) . I add value in FIFO in one thread and use it another. I have place mutex in each access (R/W) but without success.
The crash arrive randomly. I have extend stack_size to 2000, but without effect.
I have place my watch-dog mecanism like explain before and now there is no crash.In fact, crash is allways here but the automatique restart stay it without effect in my process.
My question is about what can stop a thread (or crash). Is there any risque of memory leek if i restart thread every time it crash ? What is the memory cost of this strategy?
Perhaps few volatile variables declarations may solve this ?
 
you most likely have a code causing the crash by writing out of bounds, if you cant provide us code so we can help you see where problem is (even if its complex) theres not much we can do except keep guessing. Perhaps you can try making a stripped down version that can crash so we can see the code, that may help, but not much else we can do without something to look at
 
a code causing the crash by writing out of bounds
Thanks a lot with your indication, because i take a look to my code and see one stupide mistake when i make my test to solve the problem.
I have inverted threads name when i have growed stack size parameter. I have doubled the stack size for the good thread and now all seem ok.
It's not very easy to define good stack size. Do you know one method for that ?
Best regards
Eric
 
i noticed it intermittent locking up here as well while working on my library, it turns out if i don't include threads.delay(1) OR threads.yield(), it will intermittant lock up, most of the time. I am using threads.yield() now and it seems to be running fine on the library im working on.

Now I just keep threads.yield() at end of loop() and end of thread.
 
For me it isn't the reason of my intermittent locking because all my threads include threads.yield() function. As said before the solution seem be to grow thread stack size.
It's easy to extand stack size for threads (Ex threads.addThread(thread_SendDatas,0,2048),but what about Loop() who are thread 0 if don't make mistakes ?
 
For me it isn't the reason of my intermittent locking because all my threads include threads.yield() function. As said before the solution seem be to grow thread stack size.
It's easy to extand stack size for threads (Ex threads.addThread(thread_SendDatas,0,2048),but what about Loop() who are thread 0 if don't make mistakes ?

RAM in many embedded systems, including Teensy, is divided into three parts:

1. Static variables - fixed size at the start of RAM (may also place code here)
2. Heap - allocated with new() and malloc() starting at end of static and growing up
3. Main stack - starts at the end of memory and grows down.

During normal operation, the heap expands upward while the stack expands downward, unless they both collide and the system has problems.

TeensyThreads creates a seperate stack for every thread. That stack is placed in the heap and grows down, same as the main stack. Thus, every thread's stack grows until it crashes with the heap below it. By consuming heap, it leaves less RAM for the main stack. The main stack (stack of thread 0) is unbounded. It starts at the end of memory and grows until it collides.

Usually, there's plenty of RAM and nothing will crash. Most functions don't consume much stack. Stack is consumed a lot by recursion or by having large local variables. For example, the following code will take up 80K of RAM in the stack while it is running:

Code:
int longCalc() {
  int data[20480];
  dosomething(data);
}

When it finishes, the stack will return and the RAM will be "released".

The problem with these scenarios is that "collisions" are often undetectable. Memory will just overlap and two pieces of code will overwrite each other, causing numerous obscure bugs. TeensyThreads provides a `getStackRemaining()` method to detect when you are running out of memory. It also provides a "stack_overflow_isr()" function you can override to catch this problem. The main stack does not do this.

One way to get around this is for you to put a marker in memory and see if it gets clobbered.

Code:
extern unsigned long _estack;
#define STACK_SIZE 10240/sizeof(unsigned long)  // 10KB of stack
uint32_t *memory = (uint32_t*) (&_estack - STACK_SIZE);
*memory = 0xFEFEFEFE;

Then periodically check `*memory`. If it changes, either the heap grew over this point, or the stack grew over it.

TeenyThreads assumes a 10KB main stack size. The function `getStackRemaining(0)` will return how close the main stack pointer is to reaching the limit. The size can be changed in line 183:

Code:
  const int DEFAULT_STACK0_SIZE = 10240; // estimate for thread 0?
 
Hi,

is it possible in TeensyThreads to start a thread and suspend it as long an event happens (e.g. interrupt) then process the things needed from the interrupt and then suspended (sleeping) again => so like a blocking/waiting action ?

Thank you

Torsten
 
@Torsten it should be possible with the use of semaphores, of course also there (see lock, unlock, try_lock):
just interlock the producer and consumer of your resource.
 
@Torsten it should be possible with the use of semaphores, of course also there (see lock, unlock, try_lock):
just interlock the producer and consumer of your resource.

@fab672000,

Thank you for your quick answer...yes after thinking about a bit this seems to be possible...but how to 'grep'/consume a semaphore that the thread blocks and then release it again in the irq routine..is there a function to consume a semaphore and then release it again ?

Torsten
 
So I think you want to use code like below : the idea is to test is a boolean flag (i.e.: my_resource_ready ) is true and early bail out if not which will cause the next thread to be executed so very similar to the suspend function you try to achieve here's some quick and dirty pseudo-code (not tested!) to illustrate the principle:

0. The example code assumes it has access to a common mutex variable say: mutex my_mutex and also my_resource_ready:
Code:
mutex my_mutex;
bool my_resource_ready = false;

1. Consumer thread to be suspended until event pseudo code:
Code:
my_mutex.lock(); // could also use the scoped lock_guard instance here

if (my_resource_ready)
{ 
   // do work when not suspended
   my_resource_ready = false; // means consumed
} // else we are suspended

my_mutex.unlock();


2. Then in the event producer code:

Code:
my_mutex.lock(); // could also use the scoped lock_guard instance here

my_resource_ready = true; // simplistic for the example, better code will test for overrun (i.e. resource was not consumed when new one available) or handle a queue ...
my_mutex.unlock();
 
Last edited:
Hi,

will teensythreads and interrupts work together, or will interrupts via attachInterrupt to a pin ruin the threads schedule?

Thank you

Torsten
 
A quick look at the code shows that it can potentially use IRQ_GPT1, IRQ_GPT2 (at least one of them), for the scheduler and ticks:

It will use one or both of those depending of the chip:

Code:
// ../..
  _VectorsRam[11] = threads_svcall_isr;
// ../..
  _VectorsRam[15] = threads_systick_isr; // only when not a __IMXRT1062__

If you don't mess with these you should be ok.
 
Last edited:
Ah..thank you...

So when i am using e.g. attachInterrupt(digitalPinToInterrupt(2), pin_ISR, CHANGE); it will use which interrupt.?..it says on the teensy4 pinning card that all digital pins are interrupt capable...so pin 42 is irq 42?

Torsten
 
So in all known teensy 32 bit cores I know except __MKL26Z64__ (LC), digitalPinToInterrrupt(p) gives interrupt p, so you should be ok with int 2.
Note that even for lc this true but it has so undefined holes (-1) :
#define digitalPinToInterrupt(p) ((((p) >= 2 && (p) <= 15) || ((p) >= 20 && (p) <= 23)) ? (p) : -1)
 
Hello,
I have a problem with loud clicking noises, when using the teensy threads and teensy audio at the same time.
When the teensy (4.1) plays a wav file from the sd card then there are always those loud clicks. By a usb or I2S passthrough, there are no such noises.
I tried to reduce the threads from a total of 8 to a total of 3 plus main thread, but it still keeps clicking.
Is there a way to reduce/cancel those noises?
 
Back
Top