ivanseidel / arduinothread Goto Github PK
View Code? Open in Web Editor NEW⏳ A simple way to run Threads on Arduino
License: MIT License
⏳ A simple way to run Threads on Arduino
License: MIT License
The millis()
function returns an unsigned long integer. Implicitly casting it to a signed long is a terrible idea, for several reasons:
millis()
is set, meaning the cast will result in a negative number, and all the if(time < 0)
tests will evaluate to true.last_run + interval
can overflow, and overflowing a signed number in C++ yields undefined behavior, which is always a bug._cached_next_run
will be negative and the test time >= _cached_next_run
will immediately evaluate to true, and continue to do so as long as time
is positive.All these issues can be avoided by using the proper type for timestamps: unsigned long.
Hi, i'm using that code to control with Serial and Fastleds the Leds of a Room :
https://gist.github.com/pipoblak/a83f9f7475dfe4150f183a3deb801650
And after a time, i recive that error:
ets Jan 8 2013,rst cause:4, boot mode:(3,7)
wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
Could you please provide an example combining your sensor example with sleep?
I'm developing opens source project to sustentable agriculture.
I want to know what happens when millis() overflows...
If I need to remove all threads -> reset millis() -> addition all threads back to ThreadController in main code.
Thank you and congratulation for awesome library.
It seems Thread::setInterval
and Thread::shouldRun
are very basic and key methods of Thread
class. They implement time intervals feature and I can't realize any real usecase where we have to override intervals handling as well as "enabled\disabled" handling.
At the same time Thread::shouldRun
is very hot function and it would be nice to reduce its overhead as much as possible.
So is there any reason to make those functions virtual?
A segunda condição do laço (checks <= cached_size) sempre será verdade, pois checks só é incrementada quando thread[i] != NULL. Logo o laço termina a execução apenas por causa da primeira condição (i < MAX_THREADS). Talvez a segunda condição seria (checks < cached_size), assim o laço pode terminar a execução assim que todas as threads armazenadas forem executadas.
Thread::Thread() have a problem to Arduino
can be solved with only "Thread();"
line 8
Hi,
There's a way to set the Thread interval in microseconds?
I tried to edit the "Thread.cpp" file, changing all the millis() to micros(), but it didn't work very well.
I have a clock project (White_Led_Digital_Clock).
After 49 days the threads stopped working.
Probably because, the unsigned long from millis() arrives to the max value (4294967295).
4294967295 / (1000 * 60 * 60 * 24) = 49,71026961805556 days
I want to run some code in background .
Is there any possible to do this?
In Arduino ,
I want to run some connection process as background like BT connection , LWifi Connection , etc,
for example , here i'm trying to connect LWiFi as separate process (background)
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
LWiFi.begin();
Serial.println("WiFi Begin Succeed..!");
}
void loop()
{
// put your loop code here, to run always:
Serial.Println("Loop is running");
// Assume here i want to connect LWiFi
LWiFi.connect(WIFI_AP, LWiFiLoginInfo(WIFI_AUTH, WIFI_PASSWORD));
// this statement take some time. so i want to avoid that delay
}
always run Serial.println() without any delay, and my LWiFi.connect should be run always in background .
how to do this?
Hello. Did I catch up with the use of memory? Use a common STACK for all the threads or each STACK sampling, as is the case with FreeRTOS? Thank you.
It would be great to be able to add an optional void (*arg)
argument to onRun and have that passed to your callback.
(poorly written) example
void shutoff(void (*arg)) {
uint8_t *pin = (uint8_t*)arg;
digitalWrite(pin, LOW);
}
void setup() {
Thread t1 = Thread();
t1.onRun(shutoff, 1);
Thread t1 = Thread();
t1.onRun(shutoff, 2);
}
This will dramatically simplify code by not requiring individual callbacks for each thread that perform the same function.
The library seems not to work on the ESP32.
Boards: https://github.com/espressif/arduino-esp32
I always get "error: 'Thread' has not been declared"
Using the ESP8266 boards it works fine
In my use case I'm using a single Thread to run multiple sequences of varying times. The basic flow is.
But as last_run doesn't get updated during this sequence the timer ends up firing immediately.
My single solution was to move last_run = millis
from Thread::Thread
to Thread::setInterval
Let me know if you'd like a PR but it's a pretty straight forward change.
I want to create a thread dynamically, but if the time elapsed from the start is bigger than just-created thread interval the thread is invoked immediately.
@ivanseidel
Here is an example:
#include <Thread.h>
#include <ThreadController.h>
ThreadController controll = ThreadController();
Thread *selfCancellingThread = NULL;
Thread addingThread = Thread();
void selfCancellingCallback(){
controll.remove(selfCancellingThread);
delete selfCancellingThread;
Serial.println("Thread was self-destroyed");
}
void addingCallback(){
controll.remove(selfCancellingThread);
delete selfCancellingThread;
selfCancellingThread = new Thread(selfCancellingCallback, 2000);
controll.add(selfCancellingThread);
Serial.println("Thread was added");
}
void setup() {
Serial.begin(115200);
Serial.println("Start");
addingThread.setInterval(5000);
addingThread.onRun(addingCallback);
controll.add(&addingThread);
}
void loop() {
controll.run();
}
If I increase selfCancellingThread interval to 6000, then it will be called after (6000-5000) = 1 sec at the first invocation:
...
selfCancellingThread = new Thread(selfCancellingCallback, 6000);
...
In the code below when you cache time
before the loop and thread[i]->run();
takes more time than interval to the next thread - the next thread will not be run in that run
cycle.
25 unsigned long time = millis();
26 int checks = 0;
27 for(int i = 0; i < MAX_THREADS && checks <= cached_size; i++){
28 // Object exists? Is enabled? Timeout exceeded?
29 if(thread[i]){
30 checks++;
31 if(thread[i]->shouldRun(time)){
32 thread[i]->run();
33 }
34 }
35 }
This is not so critical for code like this:
void loop() {
threadController.run();
}
because we run the next cycle right after the previous, but if run
function attached to the timer interrupt we may miss whole timer cycle. This becomes more critical if the timer frequency is low.
I guess it would be better to replace if(thread[i]->shouldRun(time))
with thread[i]->shouldRun())
which is implied to call millis()
each time.
What do you think?
I am running code with two simple thread. on one thread i have include some GSM commands and on other thread there is just print statement.
At a time i am able to run only 1 thread at a time.
here is my code plz help me out---`#include <SoftwareSerial.h>
#include <Thread.h>
#define debug 1
#define Line_RX 3 //UART RX
#define Line_TX 2 //UART TX
SoftwareSerial mySerial (Line_TX, Line_RX); //initialize software serial
int ledPin = 6;
//My simple Thread
Thread myThread1 = Thread();
Thread myThread2 = Thread();
void niceCallback1(){
// My AT commads goes here
// I am runnig 7 at command for TCP connection establishment
}
void niceCallback2(){
// right now i have included only print statement here
}
void setup() {
delay(3000);
// put your setup code here, to run once:
mySerial.begin(19200);
delay(1000);
Serial.begin(19200);
delay(1000);
myThread1.onRun(niceCallback1);
myThread1.setInterval(6000);
myThread2.onRun(niceCallback2);
myThread2.setInterval(12000);
// checks if thread should run
if(myThread1.shouldRun())
{ mySerial.println("thread 1 starting");
myThread1.run();}
// checks if thread should run
if(myThread2.shouldRun())
{
mySerial.println("thread 2 starting");
myThread2.run();}
}
void loop() {
}`
I have witnessed some confusion caused by the name of this library, with people wondering whether it implements threads. I would argue that this library should better be renamed, because it has nothing to do with threads.
The whole purpose of threads is to simplify programming by allowing the use of blocking functions and infinite loops, without fear of blocking the whole program. For example, blinking an LED with threads would be done like this:
void blink_led()
{
pinMode(ledPin, OUTPUT);
for (;;) { // infinite loop is OK
digitalWrite(LedPin, HIGH);
delay(200); // only this thread is blocked
digitalWrite(LedPin, LOW);
delay(200); // ditto
}
}
The competing paradigm is the state machine, where one has to remember the current state, and write non-blocking tasks that perform one single state transition on each call:
void blink_led() {
static bool initialized; // state variable
static bool ledState; // ditto
if (!initialized) {
pinMode(ledPin, OUTPUT);
initialized = true; // update state
}
ledState = !ledState; // update state
digitalWrite(ledPin, ledState);
}
The whole purpose of this library is to support this style of programming by taking care of the scheduling of these tasks.
Since threads and state machines are competing paradigms, and since this library is specifically designed to support the latter, calling it “ArduinoThread” is misleading. Granted, the README file starts by saying that these are not “real” threads, but it stills gives the feeling that this is somehow related to threads, or that we may have some sort of “quasi-threads”, maybe like protothreads. One has to completely understand the library in order to see that we are actually in the “opposite camp”.
It is worth noting that protothreads can be used on Arduino, and that “real” threads have been implemented on AVR microcontrollers in the form of preemptive multitasking kernels: here and here.
It shows "0" (zero) instead real values...
Can you help to fix it?
Thanks.
Great little Project and documentation! However I have a question:
Is there a way to pass function parameters to a function in a thread?
I am imagining something like mythread.run(<params>)
Hello,
I would like to do somethings like that :
#include "Thread.h"
#include "ThreadController.h"
#include <DueTimer.h>
class SensorThread: public Thread {
public:
int value;
int pin;
void run(){
value = map(analogRead(pin), 0,1023,0,255);
if(value > 1000) {
//i want to pause the main thread
doSomethings();
//i want to resume the main thread
}
runned();
}
void doSomethings(){
}
};
// Now, let's use our new class of Thread
SensorThread analog1 = SensorThread();
SensorThread analog2 = SensorThread();
// Instantiate a new ThreadController
ThreadController controller = ThreadController();
// This is the callback for the Timer
void timerCallback(){
controller.run();
}
void setup(){
Serial.begin(9600);
// Configures Thread analog1
analog1.pin = A1;
analog1.setInterval(100);
// Configures Thread analog2
analog2.pin = A2;
analog2.setInterval(100);
// Add the Threads to our ThreadController
controller.add(&analog1);
controller.add(&analog2);
Timer1.attachInterrupt(timerCallback).start(10000);
}
void loop(){
delay(1000);
Serial.print("Analog1 Thread: ");
Serial.println(analog1.value);
Serial.print("Analog2 Thread: ");
Serial.println(analog2.value);
delay(1000);
}
Do you think it's possible ?
Hi,
First awesome library. Kudos on the work.
Is is possible to have multiple threads calling the same callback ?
Is it also possible to pass arguments to the thread ? If so can you share an example ?
Thanks.
Hey there,
I am using this library with great success, thank you!
I am wondering if there is any way to programmatically change the interval time at which a thread runs at without having to remove the thread, set interval, and then re-add it to the thread controller?
Looking at ThreadController and your max size. You could've just as easily malloc'd a new block of threads when necessary. Is there any specific reason for not doing this?
How stop Thread?
Hi i am trying to run 3 motors with an arduino at the same time but all i can accomplish is running them in sequence which i dont need ArduinoThread for if someone could give me some insight or an example on how to do this i could really use the help
I have been thinking about a lightweight alternative to ThreadController
that would both require less typing from the programmer and use less RAM. Here is what I have come with, which I call ThreadList
:
template<int N> struct ThreadList {
Thread threads[N];
void operator()() {
unsigned long now = millis();
for (int i = 0; i < N; i++)
if (threads[i].shouldRun(now)) threads[i].run();
}
};
As an example usage, say we have a task foo()
to run every 200 ms, and a task bar()
to run every 500 ms. With the ThreadController
class, this would be done as follows:
Thread foo_thread(foo, 200);
Thread bar_thread(bar, 500);
ThreadController runner;
void setup()
{
runner.add(&foo_thread);
runner.add(&bar_thread);
}
void loop() {
runner.run();
}
With a ThreadList
, there is no need to create a named variable for each Thread, nor to call the add()
method of the controller. Instead, everything is handled by a single aggregate initialization:
ThreadList<2> runner = {
Thread(foo, 200),
Thread(bar, 500)
};
void setup() { } // nothing to do here
void loop() {
runner();
}
The only drawback in the syntax above is that one has to explicitly give the size of the list as a template argument.
The other benefit of ThreadList
is that it consumes 0 bytes of RAM in excess of the Threads it contains, whereas a ThreadController
is 51 bytes. It can make a difference on the smallest chips.
Now, this has its own limitations. One of them is that, if one needs to enable or disable one Thread, or change its interval, the syntax becomes clumsy:
Thread * foo_thread = &runner.threads[0];
foo_thread->enabled = false;
The other is that, not being a thread, it cannot enabled or disabled as a whole.
I was wondering whether this might be a worthy addition to the library. Not fully convinced yet. Have an opinion?
Hello,
This warning doesn't seem to have any effect but...
../ThreadController.cpp: In member function 'void ThreadController::remove(int)': ../ThreadController.cpp:68:7: warning: unused variable 'found' [-Wunused-variable] bool found = false;
The unused variable should be cleaned up by removing the declaration
void ThreadController::remove(int id){
// Find Threads with the id, and removes
bool found = false; // <--- this line
Thanks
Shound't calling:
thread_controller.remove(&thread1);
Stop the thread from firing and executing the callback ?
If not is there a method to stop a thread from executing the callback ?
Thanks.
In my program, I've created 3 threads and then added them all to a controller thread. However, one thread was never executed (I had print-statements that should have run) and after some debugging I noticed that the size of the controller thread showed 2, when it should have been 3. I did not use thread names. I am only using lambda functions as callback functions for the threads.
Looking at the thread-controllers add function, I saw that a thread is not added when the controller already has a thread with the same ID. I printed the thread-ids of all my threads and it turned out that the 1st and the 3rd thread got the same ID, so the 3rd thread was never added. But this should not be possible as different threads should get different ids?
When I added Serial.println() before and Serial.println(controller.size()) after adding the 3rd thread to the controller, all 3 threads got different IDs. I can not explain this behaviour.
Thus, my conclusion is that using memory address as ThreadID feels unpredictable. Maybe thread id could be substituted by a random number instead? (I did this as a workaround).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.