@@ -1008,15 +1008,14 @@ asyncio.run(queue_go(4))
1008
1008
1009
1009
## 3.6 ThreadSafeFlag
1010
1010
1011
- This requires firmware V1.15 or later.
1012
1011
See also [ Interfacing uasyncio to interrupts] ( ./INTERRUPTS.md ) . Because of
1013
1012
[ this issue] ( https://github.com/micropython/micropython/issues/7965 ) the
1014
1013
` ThreadSafeFlag ` class does not work under the Unix build.
1015
1014
1016
1015
This official class provides an efficient means of synchronising a task with a
1017
1016
truly asynchronous event such as a hardware interrupt service routine or code
1018
- running in another thread. It operates in a similar way to ` Event ` with the
1019
- following key differences:
1017
+ running in another thread or on another core . It operates in a similar way to
1018
+ ` Event ` with the following key differences:
1020
1019
* It is thread safe: the ` set ` event may be called from asynchronous code.
1021
1020
* It is self-clearing.
1022
1021
* Only one task may wait on the flag.
@@ -1094,26 +1093,39 @@ hardware device requires the use of an ISR for a μs level response. Having
1094
1093
serviced the device, the ISR flags an asynchronous routine, typically
1095
1094
processing received data.
1096
1095
1097
- The fact that only one task may wait on a ` ThreadSafeFlag ` may be addressed by
1098
- having a task that waits on the ` ThreadSafeFlag ` set an ` Event ` as in the
1099
- following:
1096
+ The fact that only one task may wait on a ` ThreadSafeFlag ` may be addressed as
1097
+ follows.
1100
1098
``` python
1101
1099
class ThreadSafeEvent (asyncio .Event ):
1102
1100
def __init__ (self ):
1103
1101
super ().__init__ ()
1102
+ self ._waiting_on_tsf = False
1104
1103
self ._tsf = asyncio.ThreadSafeFlag()
1105
- asyncio.create_task(self ._run())
1106
-
1107
- async def _run (self ):
1108
- while True :
1109
- await self ._tsf.wait()
1110
- super ().set()
1111
1104
1112
1105
def set (self ):
1113
1106
self ._tsf.set()
1107
+
1108
+ async def _waiter (self ): # Runs if 1st task is cancelled
1109
+ await self ._tsf.wait()
1110
+ super ().set()
1111
+ self ._waiting_on_tsf = False
1112
+
1113
+ async def wait (self ):
1114
+ if self ._waiting_on_tsf == False :
1115
+ self ._waiting_on_tsf = True
1116
+ await asyncio.sleep(0 ) # Ensure other tasks see updated flag
1117
+ try :
1118
+ await self ._tsf.wait()
1119
+ super ().set()
1120
+ self ._waiting_on_tsf = False
1121
+ except asyncio.CancelledError:
1122
+ asyncio.create_task(self ._waiter())
1123
+ raise # Pass cancellation to calling code
1124
+ else :
1125
+ await super ().wait()
1114
1126
```
1115
- An instance may be set by a hard ISR or from another thread/core. It must
1116
- explicitly be cleared. Multiple tasks may wait on it .
1127
+ An instance may be set by a hard ISR or from another thread/core. As an ` Event `
1128
+ it can support multiple tasks and must explicitly be cleared .
1117
1129
1118
1130
###### [ Contents] ( ./TUTORIAL.md#contents )
1119
1131
@@ -1331,9 +1343,8 @@ finally:
1331
1343
1332
1344
## 3.9 Message
1333
1345
1334
- This requires firmware V1.15 or later. Note that because of
1335
- [ this issue] ( https://github.com/micropython/micropython/issues/7965 ) the
1336
- ` Message ` class does not work under the Unix build.
1346
+ Because of [ this issue] ( https://github.com/micropython/micropython/issues/7965 )
1347
+ the ` Message ` class does not work under the Unix build.
1337
1348
1338
1349
This is an unofficial primitive with no counterpart in CPython asyncio. It uses
1339
1350
[ ThreadSafeFlag] ( ./TUTORIAL.md#36-threadsafeflag ) to provide an object similar
@@ -1345,6 +1356,7 @@ It is similar to the `Event` class. It differs in that:
1345
1356
* ` .set() ` is capable of being called from a hard or soft interrupt service
1346
1357
routine.
1347
1358
* It is an awaitable class.
1359
+ * It can be used in an asynchronous iterator.
1348
1360
* The logic of ` .clear ` differs: it must be called by at least one task which
1349
1361
waits on the ` Message ` .
1350
1362
@@ -1421,6 +1433,16 @@ async def main():
1421
1433
1422
1434
asyncio.run(main())
1423
1435
```
1436
+ Receiving messages in an asynchronous iterator:
1437
+ ``` python
1438
+ msg = Message()
1439
+ asyncio.create_task(send_data(msg))
1440
+ async for data in msg:
1441
+ # process data
1442
+ msg.clear()
1443
+ ```
1444
+ The ` Message ` class does not have a queue: if the instance is set, then set
1445
+ again before it is accessed, the first data item will be lost.
1424
1446
1425
1447
## 3.10 Synchronising to hardware
1426
1448
0 commit comments