8.9. ThreadSafeFlag¶
asyncio.ThreadSafeFlag je signalizacijski primitiv koji asyncio pruža za slučaj koji Event ne podržava: rukovatelj prekida treba probuditi asyncio zadatak. Prekid se okida izvan uobičajenog rasporeda petlje događaja, pa se evidencija koju asyncio.Event.set() obavlja ne može sigurno izvesti iznutra.
8.9.1. Zašto zaseban primitiv¶
asyncio.Event.set() izvodi evidenciju koja budi korutine na čekanju uz pretpostavku da se poziva iznutra iz zadatka koji petlja trenutno izvodi. Rukovatelj prekida ne zadovoljava tu pretpostavku – može se okinuti između bilo koje dvije instrukcije i oštetiti ono što je petlja bila na pola puta izvođenja.
asyncio.ThreadSafeFlag.set() napisan je tako da bude siguran u tim kontekstima. Cijena te sigurnosti je manji skup mogućnosti od Event: na ThreadSafeFlag može u danom trenutku čekati samo jedan zadatak, a zastavica se automatski resetira kada se zadatak koji čeka probudi.
8.9.2. Osnovni oblik¶
Tipična upotreba je GPIO prekid koji predaje događaj pritiska tipke asyncio zadatku:
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 izvodi se u kontekstu prekida svaki put kad se GPIO okine; sve što radi jest poziva flag.set(). Asyncio zadatak watcher u petlji poziva await na flag.wait(); svaki put kad je zastavica postavljena, zadatak se nastavlja, izvodi posao koji pritisak tipke zahtijeva, zatim se vraća na čekanje.
8.9.3. Tri metode¶
set()– označi zastavicu kao postavljenu. Ako zadatak trenutno čeka uwait(), zakaže ga za nastavak. Sigurno za poziv iz rukovatelja prekida.wait()– korutina. Blokira dok se zastavica ne postavi, zatim se vraća. Zastavica se automatski briše pri povratku – sljedeći pozivwaitponovno će blokirati do sljedećegset().clear()– izričito obriši zastavicu bez čekanja na nju. Korisno prije prvogwaitza odbacivanje bilo kakvog lažnog ranogset()koji se okinuo prije nego što je zadatak bio spreman.
8.9.4. Samo jedan čekatelj¶
Samo jedan zadatak smije u danom trenutku biti u wait(). Oblik koji aplikacija želi je jedan vlasnički zadatak za zastavicu – obično isti zadatak koji je instalirao rukovatelj prekida – pri čemu drugi zadaci komuniciraju s njim putem Event, Lock ili dijeljenih struktura podataka zaštićenih tim primitivima.
Kada tipka mora probuditi nekoliko zadataka, vlasnički zadatak je mjesto za grananje: gornji watcher mogao bi nakon svakog pritiska pozvati some_event.set(), a svi zadaci koji čekaju na some_event nastavili bi se.