8.9. ThreadSafeFlag¶
asyncio.ThreadSafeFlag är den signaleringsprimitiv som asyncio tillhandahåller för det fall som Event inte stöder: en avbrottshanterare behöver väcka en asyncio-task. Avbrottet utlöses utanför händelseloopens normala schemaläggning, så den bokföring som asyncio.Event.set() utför kan inte göras säkert inifrån det.
8.9.1. Varför en separat primitiv¶
asyncio.Event.set() kör den bokföring som väcker väntande coroutiner under antagandet att den anropas inifrån en task som loopen för närvarande kör. En avbrottshanterare uppfyller inte det antagandet – den kan utlösas mellan vilka två instruktioner som helst och korrumpera vad loopen än var halvvägs igenom att göra.
asyncio.ThreadSafeFlag.set() är skriven för att vara säker i sådana sammanhang. Avvägningen för den säkerheten är en mindre funktionsuppsättning än Event: en ThreadSafeFlag kan endast väntas på av en task i taget, och flaggan återställs automatiskt när den väntande task vaknar.
8.9.2. Grundformen¶
Ett typiskt användningsfall är ett GPIO-avbrott som lämnar över en knapptryckningshändelse till en asyncio-task:
import asyncio
from machine import Pin
flag = asyncio.ThreadSafeFlag()
def on_press(pin):
flag.set()
async def watcher():
button = Pin("P1", Pin.IN, Pin.PULL_UP)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
while True:
await flag.wait()
print("button pressed")
asyncio.run(watcher())
on_press körs i avbrottskontext varje gång GPIO utlöses; allt den gör är att anropa flag.set(). Asyncio-task watcher awaitar flag.wait() i en loop; varje gång flaggan sätts återupptas task, utför vilket arbete knapptryckningen än kräver och loopar sedan tillbaka för att vänta igen.
8.9.3. De tre metoderna¶
set()– markera flaggan som satt. Om en task för närvarande väntar iwait(), schemalägg den att återupptas. Säker att anropa från en avbrottshanterare.wait()– en coroutine. Blockera tills flaggan sätts och returnera sedan. Flaggan rensas automatiskt vid retur – nästa anrop tillwaitblockerar igen tills nästaset().clear()– rensa flaggan explicit utan att vänta på den. Användbart före ett förstawaitför att kasta bort eventuella falska tidigaset()som utlöstes innan task var redo.
8.9.4. Endast en väntare¶
Endast en task får befinna sig i wait() åt gången. Den form en applikation vill ha är en enda ägar-task för flaggan – vanligtvis samma task som installerade avbrottshanteraren – med andra tasks som kommunicerar med den via Event, Lock eller delade datastrukturer skyddade av dessa primitiver.
När en knapp måste väcka flera tasks är ägar-task platsen att förgrena ut från: ovanstående watcher kan anropa some_event.set() efter varje tryckning, och alla tasks som väntar på some_event skulle återupptas.