8.9. ThreadSafeFlag

asyncio.ThreadSafeFlag, Event sınıfının desteklemediği durum için asyncio’nun sağladığı sinyalleme ilkelidir: bir kesme işleyicisinin bir asyncio görevini uyandırması gerekir. Kesme, olay döngüsünün normal zamanlamasının dışında tetiklenir, dolayısıyla asyncio.Event.set() işleminin yaptığı kayıt tutma işlemi onun içinden güvenle yapılamaz.

8.9.1. Neden ayrı bir ilkel

asyncio.Event.set(), bekleyen coroutine’leri uyandıran kayıt tutma işlemini döngünün şu anda çalıştırdığı bir görevin içinden çağrıldığı varsayımıyla çalıştırır. Bir kesme işleyicisi bu varsayımı karşılamaz – herhangi iki komut arasında tetiklenebilir ve döngünün yarıladığı her ne işse onu bozabilir.

asyncio.ThreadSafeFlag.set(), bu bağlamlarda güvenli olacak şekilde yazılmıştır. Bu güvenliğin bedeli, Event sınıfından daha küçük bir özellik kümesidir: bir ThreadSafeFlag aynı anda yalnızca tek bir görev tarafından beklenebilir ve bekleyen görev uyandığında bayrak otomatik olarak sıfırlanır.

8.9.2. Temel yapı

Tipik bir kullanım, bir GPIO kesmesinin bir düğme basma olayını bir asyncio görevine devretmesidir:

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, GPIO her tetiklendiğinde kesme bağlamında çalışır; yaptığı tek şey flag.set() çağırmaktır. Asyncio görevi watcher, bir döngü içinde flag.wait() üzerinde await yapar; bayrak her ayarlandığında görev devam eder, düğme basışının gerektirdiği işi çalıştırır, ardından tekrar beklemek üzere döngüye geri döner.

8.9.3. Üç yöntem

  • set() – bayrağı ayarlanmış olarak işaretler. Bir görev şu anda wait() içinde bekliyorsa, onu devam etmek üzere zamanlar. Bir kesme işleyicisinden çağrılması güvenlidir.

  • wait() – bir coroutine. Bayrak ayarlanana kadar bloklar, ardından döner. Bayrak dönüşte otomatik olarak temizlenir – bir sonraki wait çağrısı, bir sonraki set() işlemine kadar yeniden bloklar.

  • clear() – bayrağı beklemeden açıkça temizler. Görev hazır olmadan önce tetiklenmiş sahte erken bir set() işlemini atmak için ilk wait öncesinde kullanışlıdır.

8.9.4. Yalnızca tek bekleyen

Aynı anda yalnızca tek bir görev wait() içinde olabilir. Bir uygulamanın istediği yapı, bayrak için tek bir sahip görevdir – genellikle kesme işleyicisini kuran görevin aynısı – diğer görevler onunla Event, Lock veya bu ilkellerle korunan paylaşılan veri yapıları aracılığıyla iletişim kurar.

Bir düğmenin birkaç görevi uyandırması gerektiğinde, dağıtımın yapılacağı yer sahip görevdir: yukarıdaki watcher, her basıştan sonra some_event.set() çağırabilir ve some_event üzerinde bekleyen tüm görevler devam eder.