|
2 | 2 |
|
3 | 3 | `Arduino_Threads`
|
4 | 4 | =================
|
| 5 | +*Note: This library is currently in [beta](#zap-caveats).* |
5 | 6 |
|
6 | 7 | [](https://github.com/arduino-libraries/Arduino_Threads/actions/workflows/compile-examples.yml)
|
7 | 8 | [](https://github.com/arduino-libraries/Arduino_Threads/actions/workflows/check-arduino.yml)
|
8 | 9 | [](https://github.com/arduino-libraries/Arduino_Threads/actions/workflows/spell-check.yml)
|
9 | 10 |
|
10 |
| -This library makes it easy to use the multi-threading capability of [Arduino](https://www.arduino.cc/) boards that use an [Mbed OS](https://os.mbed.com/docs/mbed-os/latest/introduction/index.html)-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. |
| 11 | +This library makes it easy to use the multi-threading capability of [Arduino](https://www.arduino.cc/) boards that use an [Mbed OS](https://os.mbed.com/docs/mbed-os/latest/introduction/index.html)-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. |
11 | 12 |
|
12 |
| -## :zap: Features |
| 13 | +Preeliminary **documentation** and download links for **required tooling** are available within the [`/docs`](docs/README.md) subfolder. |
| 14 | + |
| 15 | +## :star: Features |
13 | 16 | ### :thread: Multi-threaded sketch execution
|
14 |
| -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` representing a clear separation of concerns on a file level. |
| 17 | +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 **t**hread) representing a clear separation of concerns on a file level. |
15 | 18 |
|
16 | 19 | ### :calling: Easy communication between multiple threads
|
17 |
| -Easy inter-thread-communication is facilitated via a `Shared` abstraction providing thread-safe sink/source semantics allowing to safely exchange data of any type between threads. |
| 20 | +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. |
18 | 21 |
|
19 |
| -### :electric_plug: Threadsafe, asynchronous and convenient Input/Output API |
20 |
| -#### Threadsafe |
21 |
| -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 sharing a single resource: |
| 22 | +### :shield: Thread-safe I/O |
| 23 | +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: |
22 | 24 |
|
23 |
| -Imagine a 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: |
| 25 | +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 I<sup>2</sup>C bus is managed via the `Wire` library and typically follows this pattern: |
24 | 26 |
|
25 | 27 | ```C++
|
26 | 28 | /* Wire Write Access */
|
27 |
| -Wire.beginTransmission(addr); |
28 |
| -Wire.write(val); |
| 29 | +Wire.beginTransmission(address); |
| 30 | +Wire.write(value); |
| 31 | +// Interrupting the current thread e.g. at this point can lead to an erroneous state |
| 32 | +// if another thread performs Wire I/O before the transmission ends. |
29 | 33 | Wire.endTransmission();
|
30 | 34 |
|
31 | 35 | /* Wire Read Access */
|
32 |
| -Wire.beginTransmission(addr); |
33 |
| -Wire.write(val); |
34 |
| -Wire.endTransmission(); |
35 |
| -Wire.requestFrom(addr, bytes) |
| 36 | +Wire.requestFrom(address, bytes) |
36 | 37 | while(Wire.available()) {
|
37 |
| - int val = Wire.read(); |
| 38 | + int value = Wire.read(); |
38 | 39 | }
|
39 | 40 | ```
|
40 | 41 |
|
41 |
| -Since we are using [ARM Mbed OS](https://os.mbed.com/mbed-os/) which is a [preemptive](https://en.wikipedia.org/wiki/Preemption_(computing)) [RTOS](https://en.wikipedia.org/wiki/Real-time_operating_system) for achieving multi-tasking capability and under the assumption that all threads share the same priority (which leads to a [round-robin](https://en.wikipedia.org/wiki/Round-robin_scheduling) scheduling) it can easily happen that one thread is half-way through its Wire IO access when the scheduler interrupts it and schedules the next thread which in turn starts/continues/ends its own Wire IO access. |
| 42 | +Since we are using [ARM Mbed OS](https://os.mbed.com/mbed-os/) which is a [preemptive](https://en.wikipedia.org/wiki/Preemption_(computing)) [RTOS](https://en.wikipedia.org/wiki/Real-time_operating_system) for achieving multi-tasking capability and under the assumption that all threads share the same priority (which leads to a [round-robin](https://en.wikipedia.org/wiki/Round-robin_scheduling) 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. |
| 43 | + |
| 44 | +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 :fire:. |
| 45 | + |
| 46 | +`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. |
42 | 47 |
|
43 |
| -As a result this interruption by the scheduler will break Wire IO access for both devices and leave the Wire IO controller in an undefined state. :fire:. |
| 48 | +### :runner: Asynchronous |
| 49 | +The mechanisms implemented in this library allow any thread to dispatch an I/O request asynchronously and either continue its operation or [yield](https://en.wikipedia.org/wiki/Yield_(multithreading)) 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](https://en.wikipedia.org/wiki/Context_switch). An example of this can be seen [here](examples/Threadsafe_IO/Threadsafe_SPI/Threadsafe_SPI.ino). |
44 | 50 |
|
45 |
| -`Arduino_Threads` solves this problem by encapsulating a complete IO access (e.g. reading from a `Wire` client device) within a single function call which generates an IO request to be asynchronously executed by a high-priority IO thread. The high-priority IO thread is the **only** instance which actually directly communicates with physical hardware. |
| 51 | +### :relieved: Convenient API |
| 52 | +Although you are free to directly manipulate I/O requests and responses (e.g. [Threadsafe_Wire](examples/Threadsafe_IO/Threadsafe_Wire/Threadsafe_Wire.ino)) there are convenient `read`/`write`/`writeThenRead` abstractions inspired by the [Adafruit_BusIO](https://github.com/adafruit/Adafruit_BusIO) library (e.g. [Threadsafe_Wire_BusIO](examples/Threadsafe_IO/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino)). |
46 | 53 |
|
47 |
| -#### Asynchronous |
48 |
| -The mechanisms implemented in this library allow any thread to dispatch an IO request asynchronously and either continue operation or [yield](https://en.wikipedia.org/wiki/Yield_(multithreading))-ing control to the next scheduled thread. All IO requests are stored in a queue and are executed within a high-priority IO thread after a context-switch. An example of this can be seen [here](examples/Threadsafe_IO/Threadsafe_SPI/Threadsafe_SPI.ino)). |
| 54 | +## :zap: Caveats |
49 | 55 |
|
50 |
| -#### Convenient API |
51 |
| -Although you are free to directly manipulate IO requests and responses (e.g. [Threadsafe_Wire](examples/Threadsafe_IO/Threadsafe_Wire/Threadsafe_Wire.ino)) there do exist convenient `read`/`write`/`write_then_read` abstractions inspired by the [Adafruit_BusIO](https://github.com/adafruit/Adafruit_BusIO) library (e.g. [Threadsafe_Wire_BusIO](examples/Threadsafe_IO/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino)). |
| 56 | +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](https://github.com/bcmi-labs/Arduino_Threads/issues) or participating in our [discussions](https://github.com/arduino/language/discussions). |
52 | 57 |
|
53 | 58 | ## :mag_right: Resources
|
54 | 59 |
|
55 | 60 | * [How to install a library](https://www.arduino.cc/en/guide/libraries)
|
56 |
| -* [Help Center](https://support.arduino.cc/) |
57 |
| -* [Forum](https://forum.arduino.cc) |
| 61 | +* [Help Center](https://support.arduino.cc/) - Get help from Arduino's official support team |
| 62 | +* [Forum](https://forum.arduino.cc) - Get support from the community |
58 | 63 |
|
59 | 64 | ## :bug: Bugs & Issues
|
60 | 65 |
|
61 |
| -If you want to report an issue with this library, you can submit it to the [issue tracker](issues) of this repository. Remember to include as much detail as you can about your hardware set-up, code and steps for reproducing the issue. Make sure you're using an original Arduino board. |
| 66 | +If you found an issue in this library, you can submit it to the [issue tracker](issues) 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](https://support.arduino.cc/hc/en-us/articles/360020652100-How-to-spot-a-counterfeit-Arduino). |
62 | 67 |
|
63 |
| -## :technologist: Development |
| 68 | +## :technologist: Contribute |
64 | 69 |
|
65 | 70 | There are many ways to contribute:
|
66 | 71 |
|
|
0 commit comments