I have program where I have registered a cloud function, that takes a while (e.g. 5 seconds depending on the argument), that I want to spawn a new thread for so that it is not blocking for the return value of the cloud function or other threads (including the main thread running loop()). The code runs on an Argon with deviceOS 0.9.
I can see that “returning” is printed when the cloud_func is called, but I don’t get a response to my request before after seeing “thread_func done”. The thread running the thread_func seemingly has higher priority than handling the cloud function returns.
I’ve tried adding os_thread_yield() and Particle.process() where possible in the thread_func, but with no luck.
Is the cloud function handling simply a lower priority than application threads?
Not the best approach as FreeRTOS threads are not that easily discarded nor will they function properly once their object variable goes out of scope.
Once they are created they are expected to keep running.
@Antero Just to confirm @Scruffr - a better approach is to run a finite state machine (FSM) in the loop() with a state to run your heavy code that could take a while. The loop does not need to be blocked because you can have another test of progress and nibble away at it. Your cloud_function then just queues the next state and returns very quickly. In summary, you need FSM, a FIFO mode queue, and some checks in the handler to reject request if one is already running?
I’ve modified the code to run the heavy code in the loop() function, and that works fine.
My main question/concern was actually whether or not the application threads have higher priority than the thread handling cloud requests (which seems to be the case). Whether that’s a good thing or not (I’d argue that it is not a good thing that you can’t make a low-prio application thread) is debatable, but I don’t think there is any place where that is documented.
Nope, they don't and it's not the case - it rather seems to be a misconception. But as pointed out: Poor practice inside (user) threads can disrupt the performance of the entire threading system.
However, you can set the priority of your own threads
Thanks for finding that table for me ScruffR - Forgot where I found it the first time
With regarding to thread priority, I actually did try creating a thread with priority OS_THREAD_PRIORITY_DEFAULT - 1.
A thread created with that priority, should not, in my understanding, be able to block a thread at a higher priority.
I had a thread running this function (modified for simplicity):
void thread_func(void *arg) {
for (int i = 0; i < 5000; i++) {
/* some simple operation */
os_thread_yield();
delay(1);
}
}
However when that thread was running, cloud function calls were not returned from, until that thread had exited (which in this particular case would be at least 5 seconds).
Maybe @rickkas7 can chime in but for my understanding FreeRTOS threads should
not end once spawned
not get orphaned by their object variable going out of scope
mustnot access other objects before their constructor has been positively finished (e.g. by “locking” on entry or late spawning - both shown in my code)
I think we are going in a different direction now ScruffR
I agree that my first example is not the correct way. In the example you provide, does cloud_function send a response instantly?
I’ve tried a similar implementation (using a mutex instead of a boolean), but where I would not get a HTTP response before after the thread_func would finish its busy-work.
As ScruffR mentioned, you cannot stop a FreeRTOS thead or allow it to exit. Once you start it, it must stay running forever. You can use queues and thread pools to work around this limitation.
The Thread object here is a stack allocated local variable and will be deleted when the function exits. This is not supported. Thread objects must be created as a global variable or allocated with new and never deleted.
Interesting, because when I tested with your approach, I would not get my HTTP response (sent from https://console.particle.io) before after the code after my mutex was done running (which was the whole issue behind this thread). My code was also different from yours in the way that instead of doing a delay(5000);, it was
for (int i = 0; i < 1000; i++) {
delay(1);
/* write value to HW */
delay(10);
}
But I wonder if that has something to do with the delay length, as the reference document states:
"Particle.process() is also called during any delay() of at least 1 second."
That's only true withoutSYSTEM_THREAD(ENABLED) - with multi threading delay() will just yiel and give up its timeslice till the set timeout has been reached.
However, even your loop would also accumulate delay time of more than 1 second and while the docs state "any delay() of at least 1 second" it should actually read "any accumulated delay() time of at least 1 second".
But you can replace my delay(5000) with for (uint32_t ms = millis(); millis() - ms < 5000;); to get a hard blocking loop only preempted by the FreeRTOS thread manager.