Code Monkey home page Code Monkey logo

arduinothread's People

Contributors

cahek7 avatar denages avatar edgar-bonet avatar ivankravets avatar ivanseidel avatar jrbenito avatar madacol avatar mitosch avatar wvmcastro avatar zjedi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arduinothread's Issues

Improper use of signed integers

The millis() function returns an unsigned long integer. Implicitly casting it to a signed long is a terrible idea, for several reasons:

  1. After roughly 24.9 days, the most significant bit of millis() is set, meaning the cast will result in a negative number, and all the if(time < 0) tests will evaluate to true.
  2. last_run + interval can overflow, and overflowing a signed number in C++ yields undefined behavior, which is always a bug.
  3. In the lucky event that the overflow yields the expected wrap-around, _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.

Sleep example

Could you please provide an example combining your sensor example with sleep?

What happens when millis() overflows?

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.

Is there any reason or usecase to make `Thread::setInterval` and `Thread::shouldRun` virtual?

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?

Bug ThreadController::run()

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.

Using micros() in setInterval()

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.

Any Possible to run Two Threads as same time (MultiThreading)

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?

Memory usage

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.

Add optional argument to onRun

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.

last_run never updates when timer is disabled, re-enabled

In my use case I'm using a single Thread to run multiple sequences of varying times. The basic flow is.

  • Enable PIN
  • Set timer
  • ....
  • onRun
  • Disable PIN
  • Set timer (different time)

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.

Dynamically created thread bug

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();
}

Result:
arduinothreadbug

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);
...

Result:
arduinothreadbug

Using cached `time` value may slip off schedule if `run` function takes long time.

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?

second thread is not running

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() {

}`

Library name is misleading

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.

Passing Parameters to callback functions

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>)

Interrupt the main thread

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 ?

[Question] setInterval on the fly

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?

Why is there a max size at all?

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?

running multiple thread controllers

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

Lightweight alternative to ThreadController

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?

Warning when compiling ThreadController.cpp

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

Using memory address as ThreadID sometimes gives different threads the same address

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).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.