Blocking behavior across a Spark.function and Timers?

Would like to call a Spark.function which will initiate some activity that will take a few seconds to complete. The work being done during that time will not occur in Spark.function being called into and will instead occur inside the code in some Timer loops.

I put together a test and came up with some results that seem to indicate that a delay in the Spark.function method is not blocking the Timer methods. The webmethod (ie. Spark.function) gets called into and uses a delay to stop and wait. During this delay it looks like the code in the Timer methods gets executed. So it would seem that there is no blocking? That is to say their are either multiple threads or if their is one thread then that one thread continues to do work in the Timer methods but stops doing work in the Spark.function method for the duration of the delay?

Am I even close to having the right understanding of what is going on?

Thank you.

Timer timer1(100, timer1Loop);
Timer timer2(200, timer2Loop);
Timer timer3(300, timer3Loop);

void setup()
{
    Serial.begin(9600);

    Spark.function("webmethod", webmethod);

    timer1.start();
    timer2.start();
    timer3.start();
}

void loop()
{
}

int webmethod (String param1)
{
    Serial.printlnf("webmethod start");

    // wait for something to happen that is dependent upon operations
    // in timer1, timer2 and timer3
    delay(400);

    Serial.printlnf("webmethod end");
}

void  timer1Loop()
{
    Serial.printlnf("timer1Loop");
}

void  timer2Loop()
{
    Serial.printlnf("timer2Loop");
}

void  timer3Loop()
{
    Serial.printlnf("timer3Loop");
}

Here is output that shows code in the timer loops is executing during the delay.

C:\Users\joe>particle serial monitor
Opening serial monitor for com port: "COM5"
timer3Loop
timer2Loop
timer1Loop
timer1Loop
timer2Loop
timer1Loop
timer3Loop
timer1Loop
timer2Loop
timer1Loop
timer1Loop
timer3Loop
timer2Loop
timer1Loop
timer1Loop
timer2Loop
timer1Loop
webmethod start
timer3Loop
timer1Loop
timer2Loop
timer1Loop
timer1Loop
timer3Loop
timer2Loop
timer1Loop
webmethod end
timer1Loop
timer2Loop
timer1Loop
timer3Loop
timer1Loop
timer2Loop
timer1Loop
timer1Loop
timer3Loop
timer2Loop
timer1Loop
timer1Loop
timer2Loop
timer1Loop
timer3Loop

As the docs state, Software Timers are handled via FreeRTOS which donates a seperate thread for timers
https://docs.particle.io/reference/firmware/photon/#software-timers

So your application code (including Particle.function()s - don’t use Spark anymore :wink: ) is running in one FreeRTOS thread, while timers are sharing another one, and if you use SYSTEM_THREAD(ENABLED) the system gets its own thread for cloudkeeping and stuff too.

Thank you very much for clarifying.

I did read the documentation for Timer as part of trying to figure out what was going on. The closest clue I could find to maybe their maybe being a separate thread for the timer process is this:

"The timer callback is similar to an interrupt - it shouldn't block. However, it is less restrictive than an interrupt. If the code does block, the system will not crash - the only consequence is that other software timers that should have triggered will be delayed until the blocking timer callback function returns."

If the above is the only place where the separate thread behavior is mentioned then I'd like to ask particle to make this a little more explicit as the above is kind of cryptic to a novice (like me). I've been assuming that there is only one thread and if you go on that assumption then I think you'll end up wasting alot of time and effort writing single thread code. I'm thinking you'd end up putting all your code in one big loop that needs to do everything when you could instead use timers to do some of the work independently such as polling the devices and updating a global variable with the current status of that device (assuming pooling makes more sense than an IRQ). And you could set up different polling intervals for the different devices.

@JoeT, explaining threads to the average person is not always easy so a lot of documentation is kept simple. Using software timers is actually not much different than running a single loop with non-blocking timers separating code execution. Both can be preempted and both are cooperative in that any one timer callback hogging time will affect all other timers. One thing to note with software timers is that their thread’s stack is not large so timer callbacks need to be kept simple.

Software timers are good for devices that don’t use time-sensitive bit-banged interfaces (eg. onewire) due to preemption. In a recent test reading a DS18b20 onewire sensor in a software timer, the code would not work at all (returned invalid temperature) unless the time-sensitive function calls were surrounded with single-thread blocking preventing other threads from preempting the timer. This created a 95ms lockout of the system thread which I was not entirely crazy about though everything worked nonetheless.

A user can create their own threads and more functions are being exposed for managing unique resources. The Particle platform is quite sophisticated and with that comes complexity! You may want to read the System Thread section of the docs for more info. :grinning:

1 Like

The important keyword in the docs is FreeRTOS.
That is one term that wraps up all the multithreading, preemtion, time slicing, … stuff and can be investigates further on the net as it is a massive topic.

Thanks again for your insights. Think you’ve answered my main question which was to try and get a grasp of some of the basics regarding threads. Guess the best thing to do next is to put together my project and then put it out here for a review to see if I did things right.

2 Likes