Spark_wiring_thread constructor to start thread with object method

In cpp I can do this:

class Test
{
public:
  void startThreads();
private:
  int calculate(int from, int to);
}  
#include <thread>

void Test::startThreads()
{
    std::thread t1(&Test::calculate, this,  0, 10);
    std::thread t2(&Test::calculate, this, 11, 20);
    t1.join();
    t2.join();
}
int main() {
    Test obj{};
    obj.startThreads();
    return 0;
}

I’m trying to start a thread in a class like this in Particle. When I just pass the object’s method, I get an error like this:

error: no matching function for call to 'Thread::Thread(const char [10], int(Test::)(), const os_thread_prio_t&, const size_t&)'
myThread = new Thread(“My_Thread”, &Test::calculate, OS_THREAD_PRIORITY_DEFAULT, OS_THREAD_STACK_SIZE_DEFAULT);
candidates are:
In file included from …/wiring/inc/spark_wiring_watchdog.h:22:0,
from …/wiring/inc/spark_wiring_cloud.h:31,
from …/wiring/inc/spark_wiring.h:47,
from ./inc/application.h:36,
from /workspace//src/myProject.cpp:1:
…/wiring/inc/spark_wiring_thread.h:53:5: note: Thread::Thread(const char
, wiring_thread_fn_t, os_thread_prio_t, size_t)

In cpp I can use this Thread constructor to pass ‘this’ as a reference to the object.
Is this possible to do with the threads in the particle firmware?

I don’t quite get the connection between the three code blocks at the top and your error message which clearly moans about a line of code that is not present in any of the three snippets.

myThread = new Thread("My_Thread", &Test::calculate, OS_THREAD_PRIORITY_DEFAULT, OS_THREAD_STACK_SIZE_DEFAULT);

Where does this line come from?

Also “standard C++” threads and FreeRTOS threads play by different rules.

Well,

The three code blocks at the top are standard C++.

The line you copied is how I tried it with FreeRTOS threads.

I want to know if I can create a FreeRTOS thread the same way as the three code blocks I mentioned. (creating a thread with an object function)

Standard C++:
std::thread t1(&Test::calculate, this, 0, 10); // Pass “this” to get to the object’s method

Particle:
myThread = new Thread("My_Thread", &Test::calculate, OS_THREAD_PRIORITY_DEFAULT, OS_THREAD_STACK_SIZE_DEFAULT);

How can I for example pass “this” to the particle Thread constructor?

I don’t see any Thread constructor that would take a non-static object method as parameter.

But we could ping @mdma or @jvanier for this

@kenvernaillen, just a reminder that in the system firmware, you cannot destroy a thread once created.

Okay, the threads I am using are neverending loops with flags to see if they need to be paused or not.
You mean I should not join or dispose the thread?

@kenvernaillen, once created you can’t dispose of a thread. You also need to be conscious of the stack allocated to the thread. Is there any reason you are using a thread instead of a Software timer or millis() construct in loop()? Do your threads use any hardware resources or wifi/cellular/cloud functions?

@peekay123 my application is a hardware device that controls airpressure. So it needs to monitor the filling curve + send live pressure + listen to incoming commands + control multiple hardware components at the same time. Without threads, this would be very complicated I think.

@kenvernaillen, it is not necessarily complicated if you use FSMs for managing your states and non-blocking timers for timeouts, etc. If you plan on using hardware resources in your threads, you will need exclusive access of the hardware resources to prevent issues and, to be honest, I have no idea how Particle wifi/cellular/cloud functions will behave when being called from a thread. One thing to remember is that the minimum FreeRTOS timeslice is 1ms and nothing happens “at the same time” since there is only a singe processor. So your threads will get some processing time every 1ms and could be preempted by interrupts and system firmware.

@mdma would be the guy to advise.

2 Likes

@peekay123 wouldn’t adding SINGLE_THREADED_BLOCK also fix the issue of exclusive access? The reason I first thought of threads is because some of these threads are long sequences (would become very unclear if broken into pieces) and some threads need a constant connection (for example our MQTT connection) to listen for crucial commands. If one method takes too long, the mqtt client would disconnect.

@kenvernaillen, yes (possibly) to all your points though I would strongly suggest getting feedback from @mdma.