|
7 | 7 | [](https://github.com/arduino-libraries/Arduino_Threads/actions/workflows/check-arduino.yml)
|
8 | 8 | [](https://github.com/arduino-libraries/Arduino_Threads/actions/workflows/spell-check.yml)
|
9 | 9 |
|
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. |
| 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 | 11 |
|
12 |
| -## :zap: Features |
| 12 | +## :star: Features |
13 | 13 | ### :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. |
| 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` file (t suffix stands for **t**hread) representing a clear separation of concerns on a file level. |
15 | 15 |
|
16 | 16 | ### :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. |
| 17 | +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 | 18 |
|
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: |
| 19 | +### :shield: Thread-safe I/O |
| 20 | +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 | 21 |
|
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: |
| 22 | +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 | 23 |
|
25 | 24 | ```C++
|
26 | 25 | /* Wire Write Access */
|
27 |
| -Wire.beginTransmission(addr); |
28 |
| -Wire.write(val); |
| 26 | +Wire.beginTransmission(address); |
| 27 | +Wire.write(value); |
| 28 | +// Interrupting the current thread e.g. at this point can lead to an erroneous state |
| 29 | +// if another thread performs Wire I/O before the transmission ends. |
29 | 30 | Wire.endTransmission();
|
30 | 31 |
|
31 | 32 | /* Wire Read Access */
|
32 |
| -Wire.beginTransmission(addr); |
33 |
| -Wire.write(val); |
34 |
| -Wire.endTransmission(); |
35 |
| -Wire.requestFrom(addr, bytes) |
| 33 | +Wire.requestFrom(address, bytes) |
36 | 34 | while(Wire.available()) {
|
37 |
| - int val = Wire.read(); |
| 35 | + int value = Wire.read(); |
38 | 36 | }
|
39 | 37 | ```
|
40 | 38 |
|
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. |
| 39 | +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. |
| 40 | + |
| 41 | +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:. |
| 42 | + |
| 43 | +`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. |
| 44 | + |
| 45 | +### :runner: Asynchronous |
| 46 | +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)). |
| 47 | + |
| 48 | +### :relieved: Convenient API |
| 49 | +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`/`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)). |
| 50 | + |
| 51 | + |
42 | 52 |
|
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:. |
| 53 | +## :zap: Caveats |
44 | 54 |
|
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. |
46 | 55 |
|
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)). |
49 | 56 |
|
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)). |
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