Skip to content

Lightweight alternative to ThreadController #6

Closed

Description

@edgar-bonet

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?

Activity

  1. ivanseidel commented on Jun 17, 2015

    @ivanseidel
    Owner

    I like two things in it, very much:

    1. We don't need the .run(), just mythread().
    2. Memory is allocated for just what it needs

    The cons I see:
    You cannot place a ThreadList inside a ThreadList or inside a ThreadController, since it doesn't extends Thread.

    I thought in another approach to that, that for sure will not reduce to 0, but will reduce memory. One problem that causes the size to be 51 bytes, is that we ares storing an array (by default) of 15 Threads (I'm not sure how much a pointer occupies, but if that's 2 bytes per pointer, than we have 30 bytes), a solution would be passing the number of Maximum Threads with the ThreadController, we could allocate memory just for that.

    One more thing: I'm really thinking in changing the attribute enabled to something more extendable such as enabled(), and to set, use enabled(true|false).

  2. CAHEK7 commented on Aug 30, 2016

    @CAHEK7
    Contributor

    What about some C++11 template magic? This example doesn't have the main cons, so you can use that list everywhere, even inside ThreadController.

    template<int N> class ThreadList : public Thread {
        Thread threads[N];
        public:
            template <typename... T>
            ThreadList(T&&... params) : Thread(), threads{params...} {};
            void operator()() {
                run();
            }
            void run () final override {
                unsigned long now = millis();
                for (int i = 0; i < N; i++)
                    if (threads[i].shouldRun(now))
                        threads[i].run();
                runned();
            }
    };
    

    This is just a proof of concept. I can make proper implementation if the idea is interesting.

  3. ivanseidel commented on Mar 1, 2017

    @ivanseidel
    Owner

    Closing because it's already Merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions