8.9. ThreadSafeFlag#
asyncio.ThreadSafeFlag คือ primitive การส่งสัญญาณที่ asyncio มีไว้สำหรับกรณีที่ Event ไม่ รองรับ: interrupt handler ต้องการปลุกงาน asyncio ขึ้นมา interrupt ยิงนอก normal scheduling ของ event loop ดังนั้น bookkeeping ที่ asyncio.Event.set() ทำไม่สามารถทำได้อย่างปลอดภัยจากภายในมัน
8.9.1. ทำไมต้องมี primitive แยกต่างหาก#
asyncio.Event.set() ดำเนิน bookkeeping ที่ปลุก coroutine ที่กำลังรอโดยถือว่า มันถูกเรียกจากภายในงานที่ loop กำลังรันอยู่ interrupt handler ไม่ตรงตามข้อสมมตินั้น -- มันอาจยิงระหว่างคำสั่งสองคำสั่งใดก็ได้และทำให้เสียหายสิ่งที่ loop กำลังทำกลางคัน
asyncio.ThreadSafeFlag.set() ถูกเขียนให้ปลอดภัยในบริบทเหล่านั้น การแลกเปลี่ยนสำหรับความปลอดภัยนั้นคือชุดคุณสมบัติที่เล็กกว่า Event: ThreadSafeFlag สามารถรอได้โดย งานเดียว ในแต่ละขณะ และ flag จะ auto-reset เมื่องานที่รออยู่ตื่นขึ้นมา
8.9.2. รูปแบบพื้นฐาน#
การใช้งานทั่วไปคือ GPIO interrupt ส่งต่อ button-press event ไปยังงาน asyncio:
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 ทำงานใน interrupt context เมื่อ GPIO ยิง; สิ่งที่มันทำคือเรียก flag.set() เท่านั้น งาน asyncio watcher await flag.wait() ในลูป; ทุกครั้งที่ flag ถูก set งานจะทำงานต่อ, รันงานที่การกดปุ่มกำหนด, แล้วลูปกลับไปรออีกครั้ง
8.9.3. สามเมธอด#
set()-- ทำเครื่องหมาย flag ว่า set ถ้างานกำลังรอในwait()อยู่, กำหนดให้มันทำงานต่อ ปลอดภัยที่จะเรียกจาก interrupt handlerwait()-- coroutine บล็อกจนกว่า flag จะถูก set แล้วคืนค่า flag จะ ถูก clear โดยอัตโนมัติ เมื่อคืนค่า -- การเรียกwaitครั้งต่อไปจะบล็อกอีกครั้งจนกว่าจะมีset()ครั้งต่อไปclear()-- clear flag อย่างชัดเจนโดยไม่รอมัน มีประโยชน์ก่อนwaitครั้งแรกเพื่อทิ้งset()ที่เกิดขึ้นก่อนกำหนดก่อนที่งานจะพร้อม
8.9.4. Waiter เดียวเท่านั้น#
มีเพียงงานเดียวที่อาจอยู่ใน wait() ในแต่ละขณะ รูปแบบที่แอปพลิเคชันต้องการคืองาน owner เดียวสำหรับ flag -- มักเป็นงานเดียวกับที่ติดตั้ง interrupt handler -- โดยมีงานอื่นสื่อสารกับมันผ่าน Event, Lock, หรือโครงสร้างข้อมูลที่ใช้ร่วมกันที่ protected ด้วย primitive เหล่านั้น
เมื่อปุ่มต้องปลุกหลายงาน งาน owner คือที่ที่เหมาะสมสำหรับ fan out: watcher ข้างต้นสามารถเรียก some_event.set() หลังแต่ละการกด และทุกงานที่รอ some_event จะทำงานต่อ