Giter Site home page Giter Site logo

arduino_threads's Introduction

Arduino_Threads

Note: This library is currently in beta.

Compile Examples status Check Arduino status Spell Check status

This library makes it easy to use the multi-threading capability of Arduino boards that use an Mbed OS-based core library. Additionally this library provides thread-safe access to Wire, SPI and Serial which is relevant when creating multi-threaded sketches in order to avoid common pitfalls such as race-conditions and invalid state. โ€‹

Preeliminary documentation and download links for required tooling are available within the /docs subfolder.

โญ Features

๐Ÿงต Multi-threaded sketch execution

Instead of one big state-machine-of-doom you can split your application into multiple independent threads, each with it's own setup() and loop() function. Instead of implementing your application in a single .ino file, each independent thread is implemented in a dedicated .inot file (t suffix stands for thread) representing a clear separation of concerns on a file level.

๐Ÿ“ฒ Easy communication between multiple threads

Easy inter-thread-communication is facilitated via a Shared abstraction object providing thread-safe sink/source semantics allowing to safely exchange data of any type between threads.

๐Ÿ›ก๏ธ Thread-safe I/O

A key problem of multi-tasking is the prevention of erroneous state when multiple threads share a single resource. The following example borrowed from a typical application demonstrates the problems resulting from multiple threads accessing a single resource:

Imagine an embedded system where multiple Wire client devices are physically connected to a single Wire server. Each Wire client device is managed by a separate software thread. Each thread polls its Wire client device periodically. Access to the I2C bus is managed via the Wire library and typically follows this pattern:

/* Wire Write Access */
Wire.beginTransmission(address);
Wire.write(value);
// Interrupting the current thread e.g. at this point can lead to an erroneous state
// if another thread performs Wire I/O before the transmission ends.
Wire.endTransmission();

/* Wire Read Access */
Wire.requestFrom(address, bytes)
while(Wire.available()) {
  int value = Wire.read();
}

Since we are using ARM Mbed OS which is a preemptive RTOS for achieving multi-tasking capability and under the assumption that all threads share the same priority (which leads to a round-robin scheduling) it can easily happen that one thread is half-way through its Wire I/O access when the scheduler interrupts its execution and schedules the next thread which in turn starts, continues or ends its own Wire I/O access.

As a result this interruption by the scheduler will break Wire I/O access for both devices and leave the Wire I/O controller in an undefined state ๐Ÿ”ฅ.

Arduino_Threads solves this problem by encapsulating the complete I/O access (e.g. reading from a Wire client device) within a single function call which generates an I/O request to be asynchronously executed by a high-priority I/O thread. The high-priority I/O thread is the only instance which directly communicates with physical hardware.

๐Ÿƒ Asynchronous

The mechanisms implemented in this library allow any thread to dispatch an I/O request asynchronously and either continue its operation or yield control to the next scheduled thread. All I/O requests are stored in a queue and are executed within a high-priority I/O thread after a context-switch. An example of this can be seen here.

๐Ÿ˜Œ Convenient API

Although you are free to directly manipulate I/O requests and responses (e.g. Wire) there are convenient read/write/writeThenRead abstractions inspired by the Adafruit_BusIO library (e.g. Wire_BusIO).

โšก Caveats

This library is currently in BETA phase. This means that neither the API nor the usage patterns are set in stone and are likely to change. We are publishing this library in the full knowledge that we can't foresee every possible use-case and edge-case. Therefore we would like to treat this library, while it's in beta phase, as an experiment and ask for your input for shaping this library. Please help us by providing feedback in the issues section or participating in our discussions.

๐Ÿ”Ž Resources

๐Ÿ› Bugs & Issues

If you found an issue in this library, you can submit it to the issue tracker of this repository. Remember to include as much detail as you can about your hardware set-up, code and steps for reproducing the issue. To prevent hardware related incompatibilities make sure to use an original Arduino board.

๐Ÿง‘โ€๐Ÿ’ป Contribute

There are many ways to contribute:

  • Improve documentation and examples
  • Fix a bug
  • Test open Pull Requests
  • Implement a new feature
  • Discuss potential ways to improve this library

You can submit your patches directly to this repository as Pull Requests. Please provide a detailed description of the problem you're trying to solve and make sure you test on real hardware.

๐Ÿ’› Donations

This open-source code is maintained by Arduino with the help of the community. We invest a considerable amount of time in testing code, optimizing it and introducing new features. Please consider donating or sponsoring to support our work, as well as buying original Arduino boards which is the best way to make sure our effort can continue in the long term.

arduino_threads's People

Contributors

aentinger avatar cmaglie avatar dependabot[bot] avatar facchinm avatar giulcioffi avatar jacobhylen avatar per1234 avatar pnndra avatar sebromero 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

Watchers

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

arduino_threads's Issues

Bugs: Typical sketches that do not compile with `arduino-cli` (MT)

This issue contains a list of sketches which contain typical programming paradigms which break when compiling with the current version of the multi-threading supporting arduino-cli, due to the relatively simple wrapping of the whole file within a class.

1) .inot contains both function definition and declaration

Breaks_1.zip

2) Failure to register callback since all functions within the .inot` file are effectively member functions (and not free functions)

Breaks_2.zip

3) Initialisation of static variable fails (due to being a class member instead of a default global variable)

Breaks_3.zip

4) Instantiating any kind of object with constructor within the class fails (obviously)

Breaks_4.zip

One possible fix for all those issues would be to directly instantiate the threading class within the start of the inot file, then only prefix setup/loop with class name, i.e.

+class Thread_1 : public Arduino_Threads
+{
+public:
+  Thread_1 { _tabname = "Thread_1" }
+};

-void setup() {
+void Thread_1::setup() {

-void loop() {
+void Thread_1::loop() {


+Thread_1 thread_1;

@facchinm What do you think? Can you rework the arduino-cli branch to support this?
CC @pnndra

Move source code into src subfolder.

Hi @facchinm ๐Ÿ‘‹

I've been wondering if there's a need (caused by your builder modifications) for all the source files to be located in the top-level library folder or if they can be safely moved into src subfolder?

Usage of `Arduino_Threads` requires extension of `ArduinoCore-mbed` (Danger of CPU hogging)

In order to avoid CPU hogging by the main thread (loop() of *.ino file) it is necessary to add rtos::ThisThread::yield(); to ArduinoCore-mbed as shown below:

for (;;) {
	loop();
	if (arduino::serialEventRun) arduino::serialEventRun();
+	rtos::ThisThread::yield();
}

For all *.inot defined threads this is automatically done by this code executed after calling the thread's loop() function.

Since this is currently not the case rtos::ThisThread::yield(); is currently called within the main thread of each example (i.e. here) and I think we should rather avoid exposing the raw mbed API to the wider public.

Any side effects you can think of @facchinm?

CC @pnndra @giulcioffi @pennam @MaxPayne86

Shared Variables queue issue

it seems to me that the line below is wrong:
https://github.com/bcmi-labs/ArduinoThreads/blob/9f652184c5bbc5356e619b5fbc4e4791ea208de0/Arduino_Threads.h#L17

basically it's putting a reference to the current object in the queue but since the object is not copied, in case two elements are put in the queue these will contain the same pointer and when reading the value both items will return the same as they're reading the member of the object, which in the meantime may even have changed again.
https://github.com/bcmi-labs/ArduinoThreads/blob/9f652184c5bbc5356e619b5fbc4e4791ea208de0/Arduino_Threads.h#L9-L13

if we want to really have a queue of more than one item we need to allocate memory for that and push/pull values from there.

bottom line: do we really need more than one item in the queue?

inot-files not supported by Arduino IDE, library does not compile

When trying to open and run the "shared counter" example, I can never get the arduino IDE to open the .inot file type and so the compiler always throws an error when calling producer()/consumer(). Any words of wisdom to trickle down?

C:\Users\jgold\AppData\Local\Temp\.arduinoIDE-unsaved2024129-28668-1l8kexo.higr\Shared_Counter\Shared_Counter.ino: In function 'void setup()':
C:\Users\jgold\AppData\Local\Temp\.arduinoIDE-unsaved2024129-28668-1l8kexo.higr\Shared_Counter\Shared_Counter.ino:8:3: error: 'Producer' was not declared in this scope
   Producer.start();
   ^~~~~~~~
C:\Users\jgold\AppData\Local\Temp\.arduinoIDE-unsaved2024129-28668-1l8kexo.higr\Shared_Counter\Shared_Counter.ino:8:3: note: suggested alternative: 'prog_uchar'
   Producer.start();
   ^~~~~~~~
   prog_uchar
C:\Users\jgold\AppData\Local\Temp\.arduinoIDE-unsaved2024129-28668-1l8kexo.higr\Shared_Counter\Shared_Counter.ino:9:3: error: 'Consumer' was not declared in this scope
   Consumer.start();
   ^~~~~~~~

exit status 1

Compilation error: 'Producer' was not declared in this scope


Rename repository to Arduino_Threads

Hi @facchinm @pnndra โ˜•

Given that the central header file of this library is called Arduino_Threads.h and the current "fashion" of naming Arduino libraries is to prefix them with Arduino_ I suggest to rename this repository to Arduino_Threads.

Your thoughts?

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.