@@ -534,6 +534,85 @@ except IndexError:
534
534
pass
535
535
```
536
536
537
+ # 8. Threadsafe Queue
538
+
539
+ This queue is designed to interface between one or more ` uasyncio ` tasks and a
540
+ single thread running in a different context. This can be an interrupt service
541
+ routine (ISR) or code running in a different thread or on a different core.
542
+
543
+ Any Python object may be placed on a ` ThreadSafeQueue ` . If bi-directional
544
+ communication is required between the two contexts, two ` ThreadSafeQueue `
545
+ instances are required.
546
+
547
+ Attributes of ` ThreadSafeQueue ` :
548
+ 1 . It is of fixed size defined on instantiation.
549
+ 2 . It uses pre-allocated buffers of various types (` Queue ` uses a ` list ` ).
550
+ 3 . It is an asynchronous iterator allowing retrieval with ` async for ` .
551
+ 4 . It provides synchronous "put" and "get" methods. If the queue becomes full
552
+ (put) or empty (get), behaviour is user definable. The method either blocks or
553
+ raises an ` IndexError ` .
554
+
555
+ Constructor mandatory arg:
556
+ * ` buf ` Buffer for the queue, e.g. list ` [0 for _ in range(20)] ` or array. A
557
+ buffer of size ` N ` can hold a maximum of ` N-1 ` items.
558
+
559
+ Synchronous methods (immediate return):
560
+ * ` qsize ` No arg. Returns the number of items in the queue.
561
+ * ` empty ` No arg. Returns ` True ` if the queue is empty.
562
+ * ` full ` No arg. Returns ` True ` if the queue is full.
563
+ * ` get_sync ` Arg ` block=False ` . Returns an object from the queue. Raises
564
+ ` IndexError ` if the queue is empty, unless ` block==True ` in which case the
565
+ method blocks until the ` uasyncio ` tasks put an item on the queue.
566
+ * ` put_sync ` Args: the object to put on the queue, ` block=False ` . Raises
567
+ ` IndexError ` if the queue is full unless ` block==True ` in which case the
568
+ method blocks until the ` uasyncio ` tasks remove an item from the queue.
569
+
570
+ Asynchronous methods:
571
+ * ` put ` Arg: the object to put on the queue. If the queue is full, it will
572
+ block until space is available.
573
+
574
+ In use as a data consumer the ` uasyncio ` code will use ` async for ` to retrieve
575
+ items from the queue. If it is a data provider it will use ` put ` to place
576
+ objects on the queue.
577
+
578
+ Data consumer:
579
+ ``` python
580
+ async def handle_queued_data (q ):
581
+ async for obj in q:
582
+ await asyncio.sleep(0 ) # See below
583
+ # Process obj
584
+ ```
585
+ The ` sleep ` is necessary if you have multiple tasks waiting on the queue,
586
+ otherwise one task hogs all the data.
587
+
588
+ Data provider:
589
+ ``` python
590
+ async def feed_queue (q ):
591
+ while True :
592
+ data = await data_source()
593
+ await q.put(data)
594
+ ```
595
+ The alternate thread will use synchronous methods.
596
+
597
+ Data provider (throw if full):
598
+ ``` python
599
+ while True :
600
+ data = data_source()
601
+ try :
602
+ q.put_sync(data)
603
+ except IndexError :
604
+ # Queue is full
605
+ ```
606
+ Data consumer (block while empty):
607
+ ``` python
608
+ while True :
609
+ data = q.get(block = True ) # May take a while if the uasyncio side is slow
610
+ process(data) # Do something with it
611
+ ```
612
+ Note that where the alternate thread is an ISR it is very bad practice to allow
613
+ blocking. The application should be designed in such a way that the full/empty
614
+ case does not occur.
615
+
537
616
###### [ Contents] ( ./EVENTS.md#0-contents )
538
617
539
618
# 100 Appendix 1 Polling
0 commit comments