@@ -549,6 +549,16 @@ invocation lines alone should be changed. e.g. :
549
549
from uasyncio import Semaphore, BoundedSemaphore
550
550
from uasyncio import Queue
551
551
```
552
+ ##### Note on CPython compatibility
553
+
554
+ CPython will throw a ` RuntimeError ` on first use of a synchronisation primitive
555
+ that was instantiated prior to starting the scheduler. By contrast
556
+ ` MicroPython ` allows instantiation in synchronous code executed before the
557
+ scheduler is started. Early instantiation can be advantageous in low resource
558
+ environments. For example a class might have a large buffer and bound ` Event `
559
+ instances. Such a class should be instantiated early, before RAM fragmentation
560
+ sets in.
561
+
552
562
The following provides a discussion of the primitives.
553
563
554
564
###### [ Contents] ( ./TUTORIAL.md#contents )
@@ -625,15 +635,15 @@ using it:
625
635
import uasyncio as asyncio
626
636
from uasyncio import Event
627
637
628
- event = Event()
629
- async def waiter ():
638
+ async def waiter (event ):
630
639
print (' Waiting for event' )
631
640
await event.wait() # Pause here until event is set
632
641
print (' Waiter got event.' )
633
642
event.clear() # Flag caller and enable re-use of the event
634
643
635
644
async def main ():
636
- asyncio.create_task(waiter())
645
+ event = Event()
646
+ asyncio.create_task(waiter(event))
637
647
await asyncio.sleep(2 )
638
648
print (' Setting event' )
639
649
event.set()
@@ -915,6 +925,19 @@ tim = Timer(1, freq=1, callback=cb)
915
925
916
926
asyncio.run(foo())
917
927
```
928
+ Another example (posted by [ Damien] ( https://github.com/micropython/micropython/pull/6886#issuecomment-779863757 ) ):
929
+ ``` python
930
+ class AsyncPin :
931
+ def __init__ (self , pin , trigger ):
932
+ self .pin = pin
933
+ self .flag = ThreadSafeFlag()
934
+ self .pin.irq(lambda pin : self .flag.set(), trigger, hard = True )
935
+
936
+ def wait_edge (self ):
937
+ return self .flag.wait()
938
+ ```
939
+ You then call ` await async_pin.wait_edge() ` .
940
+
918
941
The current implementation provides no performance benefits against polling the
919
942
hardware. The ` ThreadSafeFlag ` uses the I/O mechanism. There are plans to
920
943
reduce the latency such that I/O is polled every time the scheduler acquires
@@ -1106,25 +1129,22 @@ finally:
1106
1129
1107
1130
## 3.9 Message
1108
1131
1109
- This is an unofficial primitive with no counterpart in CPython asyncio. It has
1110
- largely been superseded by [ ThreadSafeFlag] ( ./TUTORIAL.md#36-threadsafeflag ) .
1132
+ This is an unofficial primitive with no counterpart in CPython asyncio. It uses
1133
+ [ ThreadSafeFlag] ( ./TUTORIAL.md#36-threadsafeflag ) to provide an object similar
1134
+ to ` Event ` but capable of being set in a hard ISR context. It extends
1135
+ ` ThreadSafeFlag ` so that multiple tasks can wait on an ISR.
1111
1136
1112
- This is similar to the ` Event ` class. It differs in that:
1137
+ It is similar to the ` Event ` class. It differs in that:
1113
1138
* ` .set() ` has an optional data payload.
1114
1139
* ` .set() ` is capable of being called from a hard or soft interrupt service
1115
1140
routine.
1116
1141
* It is an awaitable class.
1117
-
1118
- Limitation: ` Message ` is intended for 1:1 operation where a single task waits
1119
- on a message from another task or ISR. The receiving task should issue
1120
- ` .clear ` .
1142
+ * The logic of ` .clear ` differs: it must be called by at least one task which
1143
+ waits on the ` Message ` .
1121
1144
1122
1145
The ` .set() ` method can accept an optional data value of any type. The task
1123
- waiting on the ` Message ` can retrieve it by means of ` .value() ` . Note that
1124
- ` .clear() ` will set the value to ` None ` . One use for this is for the task
1125
- setting the ` Message ` to issue ` .set(utime.ticks_ms()) ` . The task waiting on
1126
- the ` Message ` can determine the latency incurred, for example to perform
1127
- compensation for this.
1146
+ waiting on the ` Message ` can retrieve it by means of ` .value() ` or by awaiting
1147
+ the ` Message ` as below.
1128
1148
1129
1149
Like ` Event ` , ` Message ` provides a way a task to pause until another flags it
1130
1150
to continue. A ` Message ` object is instantiated and made accessible to the task
@@ -1136,8 +1156,7 @@ from primitives.message import Message
1136
1156
1137
1157
async def waiter (msg ):
1138
1158
print (' Waiting for message' )
1139
- await msg
1140
- res = msg.value()
1159
+ res = await msg
1141
1160
print (' waiter got' , res)
1142
1161
msg.clear()
1143
1162
@@ -1155,15 +1174,44 @@ and a task. The handler services the hardware and issues `.set()` which is
1155
1174
tested in slow time by the task.
1156
1175
1157
1176
Constructor:
1158
- * Optional arg ` delay_ms=0 ` Polling interval .
1177
+ * No args .
1159
1178
Synchronous methods:
1160
1179
* ` set(data=None) ` Trigger the message with optional payload.
1161
- * ` is_set() ` Return ` True ` if the message is set.
1162
- * ` clear() ` Clears the triggered status and sets payload to ` None ` .
1180
+ * ` is_set() ` Returns ` True ` if the ` Message ` is set, ` False ` if ` .clear() ` has
1181
+ beein issued.
1182
+ * ` clear() ` Clears the triggered status. At least one task waiting on the
1183
+ message should issue ` clear() ` .
1163
1184
* ` value() ` Return the payload.
1164
1185
Asynchronous Method:
1165
1186
* ` wait ` Pause until message is triggered. You can also ` await ` the message as
1166
- per the above example.
1187
+ per the examples.
1188
+
1189
+ The following example shows multiple tasks awaiting a ` Message ` .
1190
+ ``` python
1191
+ from primitives.message import Message
1192
+ import uasyncio as asyncio
1193
+
1194
+ async def bar (msg , n ):
1195
+ while True :
1196
+ res = await msg
1197
+ msg.clear()
1198
+ print (n, res)
1199
+ # Pause until other coros waiting on msg have run and before again
1200
+ # awaiting a message.
1201
+ await asyncio.sleep_ms(0 )
1202
+
1203
+ async def main ():
1204
+ msg = Message()
1205
+ for n in range (5 ):
1206
+ asyncio.create_task(bar(msg, n))
1207
+ k = 0
1208
+ while True :
1209
+ k += 1
1210
+ await asyncio.sleep_ms(1000 )
1211
+ msg.set(' Hello {} ' .format(k))
1212
+
1213
+ asyncio.run(main())
1214
+ ```
1167
1215
1168
1216
## 3.10 Synchronising to hardware
1169
1217
0 commit comments