Teensy 3.x multithreading library first release

as tni pointed out you need this:

Code:
void readSensor(){
while(1) {
  float ypr[3]; // yaw pitch roll
  my3IMU.getYawPitchRoll(ypr);
  yaw = ypr[0];
  pitch = ypr[1];
  roll = ypr[2];
}
}

also the float is local only to that scope and not using the global one, fyi
 
Thanks tni. Now I feel like an idiot. What a stupid error.

tonton81. What is did was create roll, pitch, yaw as atomics for the global scope. Have to see if I really need to do that now.
 
im not using atomics nor volatiles, perhaps its how i coded my scopes not sure, but all good here only using mutex scope locks

its also good to think of a mutex lock like an isr, keep it short as possible so others can lock on it too

function {
{mutex lock
/do whatever
}

update variable

{ mutex lock
/do something
}

update variable
}

this badly coded :p function gives 2 chances for other threads to lock before it completes, instead of holding it the entire time, gives other code runtime as well to speed things up
 
Last edited:
I just set up my threads like this:
Code:
 void readSensor(){
 while(1){
  my3IMU.getYawPitchRoll(ypr);
  threads.delay(50);
 }
}

void readSensor1(){
 while(1){
  my3IMU1.getYawPitchRoll(ypr1);
    threads.delay(50);
 }
}

and I stopped using atomics as well. The two sensors are giving me very similar results without any thread locks. Interesting though if I use this construct:
Code:
void readSensor(){
 while(1){
  Threads::Scope scope(wire_lock);
  my3IMU.getYawPitchRoll(ypr);
  threads.delay(50);
 }
}

void readSensor1(){
 while(1){
  Threads::Scope scope(wire_lock);
  my3IMU1.getYawPitchRoll(ypr1);
    threads.delay(50);
 }
}

It just hangs. By the way I did change the private to protected in the libraries. (didn't do it in wire or the spi library proper though)
 
you didnt scope it properly, so the lock never removed, and thats why it "deadlocked". this is because your while loop never exits and the scope lock was basically permanent, and the other accesses to wire_lock will never ever happen
try this:

Code:
void readSensor() {
  while (1) {
    { Threads::Scope scope(wire_lock);
      my3IMU.getYawPitchRoll(ypr);
      threads.delay(50);
    }
  }
}

void readSensor1() {
  while (1) {
    { Threads::Scope scope(wire_lock); // start of mutex scope lock
      my3IMU1.getYawPitchRoll(ypr1);
      threads.delay(50);
    } // end of mutex scope lock
  } // end of while loop
} // end of function

notice the brackets surrounding the mutex scope? :)
 
Last edited:
Thanks tonton81. Will give it a try. I saw your previous posts but wasn't sure if I needed them or not since they were enclosed in the while brackets. Lessons learned.
 
yeah, tricky a bit, but since the while never exits, neither will the lock, so it needs to be enclosed in brackets as well in order to escape the lock while in the while loop

while (never ends) {

{ <-- we start a new scope within the while loop
mutex lock
//blah
} <-- we close the scope of the mutex, automatically unlocks mutex

} <-- this while loop never gets past this point, but the one above did, so as it cycles, the scope inside is created and destructed every while cycle
 
Last edited:
you didnt scope it properly, so the lock never removed, and thats why it "deadlocked". this is because your while loop never exits and the scope lock was basically permanent, and the other accesses to wire_lock will never ever happen
try this:

Code:
void readSensor() {
  while (1) {
    { Threads::Scope scope(wire_lock);
      my3IMU.getYawPitchRoll(ypr);
      threads.delay(50);
    }
  }
}

void readSensor1() {
  while (1) {
    { Threads::Scope scope(wire_lock); // start of mutex scope lock
      my3IMU1.getYawPitchRoll(ypr1);
      threads.delay(50);
    } // end of mutex scope lock
  } // end of while loop
} // end of function

notice the brackets surrounding the mutex scope? :)

In a case like this, you might be better off with accessing the Mutex directly.

Code:
void readSensor() {
  while (1) {
      wire_lock.lock()
      my3IMU.getYawPitchRoll(ypr);
      wire_lock.unlock();
      threads.delay(50);
  }
}

You probably want to unlock before calling threads.delay(50). If not, you will still have the lock, it will do the context switch, go to the next thread, try to grab the lock, fail, switch back and then keep going. With so much switching, your delay may not be very accurate and it won't have the intended effect of letting other threads work.

If you unlock before the threads.delay(50), the other thread will be able to grab the lock and do it's work.
 
or this:

Code:
void readSensor() {
  while (1) {
    { Threads::Scope scope(wire_lock);
      my3IMU.getYawPitchRoll(ypr);
    }
      threads.delay(50); <--- this happens outside of the lock so others can use the lock
  }
}

void readSensor1() {
  while (1) {
    { Threads::Scope scope(wire_lock);
      my3IMU1.getYawPitchRoll(ypr1);
    }
      threads.delay(50); <--- this happens outside of the lock so others can use the lock
  }
}

myself i dont use delays in my sketch, only millis() is used when needed, but that and variable work dont need to be locked.
 
Last edited:
Didn't work until I downloaded the latest version. I was 1 revision off. Now it is working fine.

Thanks tonton81.

By the way I checked out those lcd screens and they give me all sorts of ideas.
 
What library are you using? Love the vids. I use my visualization tools for imu's all the time as well as a simple compass :) for debugging so I can relate ;)
 
ftrias and tonton81. I changed to use the lock directly and removed the delays. Works just as well.

ftrias if I can ask a question. Why would it be better in this case to use the lock directly as opposed to scoping it?
 
library is called geniearduino, its made to work for those screens, all the images and optional code are on the lcd uSD card, the arduino, or in this case, teensy, is the host. we still need to deal for the wait for ack/nak response so making teensythreads work with this kind of issue is awesome
 
mjs513, i read somewhere where if a function breaks before you mutex.unlock() you may deadlock, whereas the scope lock is safer as any time you exit the scope it automatically unlocks

yeah i hate delays, dont use them if you dont have to :)
 
tonton81. I know what you mean about delays. I only use them if I have no other choice like waiting for a sonar reading to come back (have no real choice). With that said using threads for the sensors seem to alleviate that problem as far as it concerns my application. Other application is motor control, have to use a delay but I then to get around that by using Pauls elapsed time library. Threads.delay seem to work differently, at least to me in that it allow other threads to work while it is in a delay state.
 
Yes it is. I love my elaspsedMillis library. Thank you Paul!

I wonder what the record is for posts in one day.
 
Enjoying watching - Looks like good progress - and good utility from threading away when otherwise waiting would be needed for a transfer.

I played more with Zilch when I saw it - that seemed nice. It seems this scheme uses more native processor threading for pre-emption - but I have not had time to try anything.

Somehow over 2 years and two months stats on this user are a ridiculous :: Posts Per Day 5.21
 
I played more with Zilch when I saw it - that seemed nice. It seems this scheme uses more native processor threading for pre-emption - but I have not had time to try anything.

I did not see Zilch when I looked at the problem of threading before creating TeensyThreads. As you note, the difference is that TeensyThreads is pre-emptive and more akin to threads in desktop operating systems, although it also has cooperative features like yield() and delay() that hands time to other tasks. But the purely cooperative model of Zilch might work better in some circumstances and the API is simple. If I had known about Zilch, I probably would have worked to add pre-emption to Zilch rather than build from scratch.

I wonder if it might be a good idea to have an official directory of Teensy libraries.
 
With a Wiki folks could self reference topics area to specific libs like this and other threads do. Except the {forum} meta data linking threads is missing with no logical structure or index. Forum's Built in search is only good for single 'good' keywords - and then you can get a list to scan of threads to then scan posts ... Bing or other does well grabbing everything shortly after posting - but you still need the right word list to hit a topic/post.

Sorry I didn't jump in with a ZILCH note when you started. I think the schemes seem different enough to maybe be better with this fresh start - I scanned Zilch - it creates a task list and does fast swapping manually when a thread yields.

I have not looked into this at all - and as apparent from my post much earlier - I didn't understand the true extent of the pre-emption. As noted above I assume this uses native processor task swapping to good effect?

I ran a test on Zilch versus standard loop() and it seemed to lose very little in swapping tasks - in fact it gained more from losing the yield(){ serialEvent()... } overhead than it added as I saw it. IIRC I did a fast bit toggle and then read the frequency to see that and Zilch could do it faster as I tried it so the net overhead wasn't a negative - I wonder what this would do? What is the time lost in task switching?

Zilch seemed like a nice idea - but wasn't sure where the gain would come in ... The value in this is that a thread stalled on a read can have the CPU handed over to another task to continue progress as demonstrated with the multiple devices as used in this thread - that was good to see.

This won't help on my current task - but looking forward to see how it works out.
 
Last edited:
ftrias. I think Paul maintains a list of libraries on the prjc website. Check here: https://www.pjrc.com/teensy/td_libs.html,

I just took a look at the Zilch thread and some of the examples. I took a look at a lot of the scheduler type libs and kind of discarded (not that they were not good mind you) for my purposes. To be honest think this lib is better for concurrency. It also follows allot of the C++ standard of threading. So thank you ftrias.
 
Last edited:
Back
Top