managing multiple threads

I recently started a project like fire alarm system. Basically, I need a thread keep monitoring the situation (like the signal from a flame sensor) at fairly high frequency (100Hz). Simultaneously, I would like the controller to do something else, which also involves timing, delays etc.

If I use scoop, there the program will look like:

thread A: has sleep(10);
thread B: has sleep(250); some code; sleep (100); some code (50); etc.
thread C: has sleep(1000); some code; sleep (200); some code (800); etc.
.....

But every time, if the thread A detects a fire, I would like some of the other thread respond immediately. Even if during their sleep. Now, all I can do is split all the long sleeps of the slave threads into something like 10 times loop of sleep(25); check if there is an alarm. But this will make code quiet complex.

Alternatively, I can use freeRtos. But I don't find a better solution. Because on the website of freeRtos, it suggests not kill any task or create new during run. So I guess, there is not a master task-slave task mechanism in the freeRtos neither. One of the differences between the freeRtos and the multi-thread lib like scoop is in the freertos, one can specify the priority ,while in the scoop one can't (please correct me if I am wrong).

So any idea to achieve this? Ideally, if one thread can be the master and can control everythign of all the other thread, it would be very very powerful and versatile, because the program can dynamically adjust the resource and the state of treads/tasks.

Does a delay of 1000 ms or less really matter for your application?

Yes. That's why I want to go multi-thread.

1000ms is quiet a lot for a robot. And that is just an example. A longer delay can be applied.

I think in general it is the case for a robot. If a robot found a car in front of it, it probably immediately jump out of the loop calculating its routine back home and release the control of the driving wheels maybe. Even without a delay in this navigation loop, one may have to put the emergency stop "if aaa, goto end of code block" in between every calculation line. Otherwise, some some unexpected delay may happen.

Or, consider a little music keyboard which could generate sound wave and drive a speaker. Human are very sensitive to delays between key stroke motion and the reaction (the attack of the sound generated). You can imagine in a lot scenarios which require some kind of real time reaction.

Again, I think the arduino system (both the hardware and the software) are more than sufficient to have some real-time behavior. Maybe, There are some way to implement this without losing too much simplicity of arduino system.

Thanks in advance.

joedodo:
Maybe, There are some way to implement this without losing too much simplicity of arduino system.

Maybe trying to use multiple threads is not the right solution to your problem.

If you have several bits of some_code() to run, put 'em in non-blocking functions and call them from the main loop()

Time them with millis() if you need to.

Yours,
TonyWilk

Thanks. looks like I can do the following: Still use the multi thread method. But instead of using sleep() in slave threads, use millis()

TonyWilk:
Maybe trying to use multiple threads is not the right solution to your problem.

If you have several bits of some_code() to run, put 'em in non-blocking functions and call them from the main loop()

Time them with millis() if you need to.

Yours,
TonyWilk

Thanks Tony again. But I think the problem I have could be a very general one when one encounters some multiple-input/output application. Powerful platforms like due have sufficient resource to do a lot things.

I put an example:
https://forum.arduino.cc/index.php?topic=523123.0

What you don't seem to grasp is that any 'multitasking', 'multithreading', 'taskswitching' OS/Library is not doing anything special.

The processor is still running one thing at a time and either preemptively or cooperatively interleaving tasks, you can (obviously) write your own code to do exactly the same thing.

What I was trying to say was: When you "encounter some multiple-input/output application" on limited hardware, it may be an advantage to interleave tasks to suit that application rather than trying to work around some 'general purpose' framework.

Yours,
TonyWilk

I know how multi-task is handled by the mcu. But it can be different...
Like you mentioned, a real "blocking task" (a delay(), for example) can't be interrupted unless one reset the board either using software watch dog or hardware one. And resetting the board will interrupt all the tasks of the system.

In the parallel mode (freeRTOS), however, a "blocking task" is not really blocking, because the scheduler will switch to different tasks automatically due to their priority.

Mega 2560 has 54 digital ios and analog ones. If I put all the tasks together in the same main loop, it will become very messy and make the development unnecessarily long, complex which is against the simplicity philosophy of arduino.

My project is very big and I am investigating multiple platforms/systems. I was really cheered up when I knew the freeRTOS was on arduino so expected the full feature of it.

But if arduino doesn't support this, it is okay. I may just change the plan to use rpi or something else and still thank you guys pointing out this.

joedodo:
In the parallel mode (freeRTOS), however, a "blocking task" is not really blocking, because the scheduler will switch to different tasks automatically due to their priority.

Good luck with that... you will encounter tasks which don't want to be interrupted, so they use
e.g. taskENTER_CRITICAL()

My project is very big and I am investigating multiple platforms/systems. I was really cheered up when I knew the freeRTOS was on arduino so expected the full feature of it.

Ok, good idea to look at all the options - there's always more than one way to skin a cat !

Just a final tale...

A while ago (!) had to develop a casino game for Automatic roulette apparatus.
The table had a huge membrane keypad with buttons for all roulette bets (single,corner,street,R/B,odd/even), a matrix of about 100 buttons to scan. Under the keypad was an array of 37 lamps to light the numbers. The wheel had a motor, wheel opto, a ball detector, a servo ball return and a servo ball release motor. The back panel had two 7-segment LED digits per bet position - a total of just under 200 7-segment displays and some more lamps. It had a multi-coin mechanism and a couple of payout mechs.
One processor ran all that lot while generating sound and lighting effects and producing 8kHz ADPCM speech in interrupts.
It was a 4MHz Z80, a UNO would've been a breeze :slight_smile:

Yours,
TonyWilk

wow that is a lot for a 4MHz processor.

From freeRTOS, some other people requested the same thing, they call it "hard thread termination", and Richard said he doesn't implement it in freeRTOS:

Tony, you must be a very experienced embedded/electronics engineer/scientist. So a question may be you can ask:
Is this "hard termination" very common in rtos? Or it is in generally rare, and rarely people use it? Thats why vwords is so expensive?

I just started playing with arduino, and never write programs for MCUs before. So is still quite ignorant. Since the neural networks are going to beat some of us. I thought the rtos kernels are like: "do whatever you like, human, I will arrange everything for you".

I will check the progress of freeRTOS from time to time.

joedodo:
Is this "hard termination" very common in rtos? Or it is in generally rare, and rarely people use it?

I must admit I've never used FreeRTOS (but knew there had to be some ENTER_CRITICAL function), I think some local guys have used it for a commercial project tho, sounds quite reasonable.

It sounds like "hard termination" is the sort of thing people end up wanting when they write code for a thread which carries on running and the parent code wants it to STOP RIGHT NOW !!!

Thread termination is a "problem" with any rtos if you let it be a problem.

If you use it in cooperative mode, it is up to you to make sure your threads do as little as possible then yield/sleep. Very much the same as writing an interrupt service routine.

If you write a thread which keeps running in loops in a CRITICAL section then it will 'break' the whole purpose of using the rtos.

If it's using preemptive taskswitching you have to keep in mind that some delicate tasks will break if the switch happens in the middle, so you have to wrap that in CRITICAL (while keeping in mind the effect this may have on your other threads).

Have a play with it, might do myself now :slight_smile:

Just keep in mind that you still have to think about how the processor is going to manage all your stuff, writing a thread is not the same as writing any old 'main-line code' - it has to 'play fair' to let other threads do their thing too.

Yours,
TonyWilk

You are right Tony, for slave tasks using taskENTER_CRITICAL(), interrupt could not interrupt them arbitrarily.

So I think it is better to use mutex in a task if one wants to interrupt it anytime.

And, yes, to design a multi task version program which has the functions of a single thread version requires extra effort unless the multi task never talk to each other and run as if they were on different computers.