Megszakításkezelők írása¶
Megfelelő hardveren a MicroPython lehetővé teszi megszakításkezelők írását Pythonban. A megszakításkezelőket - más néven megszakítás-kiszolgáló rutinokat (ISR-eket) - visszahívási függvényekként definiáljuk. Ezek valamilyen esemény, például egy időzítő kioldódása vagy egy láb feszültségváltozása hatására hajtódnak végre. Ilyen események a program kódjának végrehajtása során bármikor bekövetkezhetnek. Ennek jelentős következményei vannak, amelyek közül némelyik kifejezetten a MicroPython nyelvre jellemző. Mások minden olyan rendszerre érvényesek, amely képes valós idejű eseményekre reagálni. Ez a dokumentum először a nyelvspecifikus kérdéseket tárgyalja, majd rövid bevezetést nyújt a valós idejű programozásba azok számára, akik most ismerkednek vele.
Ez a bevezető olyan homályos kifejezéseket használ, mint a „lassú” vagy „a lehető leggyorsabb”. Ez szándékos, mivel a sebességek alkalmazásfüggők. Egy ISR esetén elfogadható időtartam a megszakítások bekövetkezésének gyakoriságától, a főprogram jellegétől és más egyidejű események jelenlététől függ.
Tippek és ajánlott gyakorlatok¶
Ez összefoglalja az alább részletezett pontokat, és felsorolja a megszakításkezelő kódjára vonatkozó fő ajánlásokat.
Tartsd a kódot a lehető legrövidebbnek és legegyszerűbbnek.
Kerüld a memóriafoglalást: ne fűzz hozzá listákhoz, ne illessz be szótárakba, és ne használj lebegőpontos számokat.
Az előbbi korlátozás megkerüléséhez fontold meg a
micropython.schedulehasználatát.Ahol egy ISR több bájtot ad vissza, használj előre lefoglalt
bytearrayobjektumot. Ha több egész számot kell megosztani egy ISR és a főprogram között, fontolj meg egy tömböt (array.array).Ahol az adatokat a főprogram és egy ISR megosztja, fontold meg a megszakítások letiltását mielőtt a főprogramban hozzáférnél az adatokhoz, majd közvetlenül utána azok újraengedélyezését (lásd Kritikus szakaszok).
Foglalj le egy vészhelyzeti kivételpuffert (lásd alább).
MicroPython-specifikus kérdések¶
A vészhelyzeti kivételpuffer¶
Ha hiba történik egy ISR-ben, a MicroPython nem tud hibajelentést készíteni, hacsak nem hozunk létre erre a célra egy speciális puffert. A hibakeresés egyszerűbb, ha az alábbi kódot beillesztjük minden megszakításokat használó programba.
import micropython
micropython.alloc_emergency_exception_buf(100)
A vészhelyzeti kivételpuffer csak egyetlen kivétel veremkövetését képes tárolni. Ez azt jelenti, hogy ha egy kivétel kezelése közben egy második kivétel keletkezik, miközben a halom zárolva van, akkor a második kivétel veremkövetése felülírja az eredetit - még akkor is, ha a második kivétel hibátlanul kezelve lett. Ez zavaró kivételüzenetekhez vezethet, ha a puffert később kiírjuk.
Egyszerűség¶
Számos okból fontos, hogy az ISR-kódot a lehető legrövidebben és legegyszerűbben tartsuk. Csak azt szabad megtennie, amit közvetlenül az őt kiváltó esemény után azonnal el kell végezni: a halasztható műveleteket a főprogram ciklusára kell bízni. Egy ISR jellemzően a megszakítást kiváltó hardvereszközzel foglalkozik, felkészítve azt a következő megszakítás bekövetkezésére. A főciklussal a megosztott adatok frissítésével kommunikál, jelezve, hogy a megszakítás bekövetkezett, majd visszatér. Egy ISR-nek a lehető leggyorsabban vissza kell adnia a vezérlést a főciklusnak. Ez nem kifejezetten MicroPython-specifikus kérdés, ezért részletesebben alább tárgyaljuk.
Kommunikáció egy ISR és a főprogram között¶
Általában egy ISR-nek kommunikálnia kell a főprogrammal. Ennek legegyszerűbb módja egy vagy több megosztott adatobjektumon keresztül történik, amelyeket vagy globálisként deklarálunk, vagy egy osztályon keresztül osztunk meg (lásd alább). Ennek számos korlátja és veszélye van, amelyeket alább részletesebben tárgyalunk. Egész számokat, bytes és bytearray objektumokat gyakran használnak erre a célra, az array modulból származó tömbökkel együtt, amelyek különféle adattípusokat tudnak tárolni.
Objektummetódusok használata visszahívásként¶
A MicroPython támogatja ezt a hatékony technikát, amely lehetővé teszi egy ISR számára, hogy példányváltozókat osszon meg a mögöttes kóddal. Lehetővé teszi továbbá, hogy egy eszközmeghajtót megvalósító osztály több eszközpéldányt is támogasson. A következő példa két LED-et villogtat különböző ütemben.
import machine
import micropython
micropython.alloc_emergency_exception_buf(100)
class Foo(object):
def __init__(self, freq, led):
self.led = led
self.timer = machine.Timer(-1, freq=freq, callback=self.cb, hard=True)
def cb(self, tim):
self.led.toggle()
red = Foo(1, machine.LED("LED_RED"))
green = Foo(0.8, machine.LED("LED_GREEN"))
Ebben a példában a red példány egy 1 Hz-es virtuális időzítőről vezérli a piros LED-et: az időzítő minden kioldásakor a red.cb() hívódik meg, átkapcsolva a piros LED-et. A green példány hasonlóan működik, egy 0,8 Hz-es időzítővel kapcsolgatva a zöld LED-et. A példánymetódusok használata két előnnyel jár. Először is egyetlen osztály lehetővé teszi a kód megosztását több hardverpéldány között. Másodszor, mivel kötött metódusról van szó, a visszahívási függvény első argumentuma a self. Ez lehetővé teszi a visszahívás számára, hogy hozzáférjen a példányadatokhoz, és állapotot mentsen az egymást követő hívások között. Például ha a fenti osztálynak lenne egy self.count változója, amelyet a konstruktorban nullára állítunk, a cb() növelhetné a számlálót. A red és green példányok ezután egymástól függetlenül tartanák nyilván, hányszor változott meg az egyes LED-ek állapota.
Python-objektumok létrehozása¶
Az ISR-ek nem hozhatnak létre Python-objektumpéldányokat. Ennek oka, hogy a MicroPythonnak memóriát kell lefoglalnia az objektum számára a szabad memóriablokkok tárolójából, amelyet heap-nek nevezünk. Ez nem megengedett egy megszakításkezelőben, mert a halomfoglalás nem újrabelépő. Más szóval a megszakítás akkor is bekövetkezhet, amikor a főprogram éppen egy foglalás közepén tart - a halom épségének megőrzése érdekében az értelmező nem engedélyez memóriafoglalást az ISR-kódban.
Ennek következménye, hogy az ISR-ek nem használhatnak lebegőpontos aritmetikát; ez azért van, mert a lebegőpontos számok Python-objektumok. Hasonlóképpen egy ISR nem fűzhet elemet egy listához. A gyakorlatban nehéz lehet pontosan meghatározni, mely kódszerkezetek kísérelnek meg memóriafoglalást és váltanak ki hibaüzenetet: ez egy újabb ok arra, hogy az ISR-kódot rövidnek és egyszerűnek tartsuk.
Ennek a problémának egyik elkerülési módja, ha az ISR előre lefoglalt puffereket használ. Például egy osztálykonstruktor létrehoz egy bytearray példányt és egy logikai jelzőt. Az ISR-metódus adatokat rendel a puffer pozícióihoz, és beállítja a jelzőt. A memóriafoglalás a főprogram kódjában történik, amikor az objektum példányosul, nem pedig az ISR-ben.
A MicroPython könyvtár I/O-metódusai általában lehetőséget biztosítanak előre lefoglalt puffer használatára. Például a machine.I2C.readfrom_into() egy hívó által megadott módosítható pufferbe olvas: ez lehetővé teszi az ISR-ben való használatát.
Egy objektum osztály vagy globálisok használata nélküli létrehozásának egy módja a következő:
def set_volume(t, buf=bytearray(3)):
buf[0] = 0xa5
buf[1] = t >> 4
buf[2] = 0x5a
return buf
A fordító a buf alapértelmezett argumentumot a függvény első betöltésekor példányosítja (általában amikor az őt tartalmazó modult importáljuk).
Objektumlétrehozás akkor is történik, amikor egy kötött metódusra mutató hivatkozás jön létre. Ez azt jelenti, hogy egy ISR nem adhat át kötött metódust egy függvénynek. Az egyik megoldás, ha az osztálykonstruktorban létrehozunk egy hivatkozást a kötött metódusra, és ezt a hivatkozást adjuk át az ISR-ben. Például:
class Foo():
def __init__(self):
self.bar_ref = self.bar # Allocation occurs here
self.x = 0.1
self.tim = machine.Timer(-1, freq=2, callback=self.cb, hard=True)
def bar(self, _):
self.x *= 1.2
print(self.x)
def cb(self, t):
# Passing self.bar would cause allocation.
micropython.schedule(self.bar_ref, 0)
További technikák, hogy a metódust a konstruktorban definiáljuk és példányosítjuk, vagy hogy a Foo.bar() metódust a self argumentummal adjuk át.
Python-objektumok használata¶
Az objektumokra vonatkozó további korlátozás a Python működési módjából adódik. Amikor egy import utasítás végrehajtódik, a Python-kód bytecode-ra fordul, ahol egy sornyi kód jellemzően több bájtkódra képeződik le. A kód futtatásakor az értelmező minden egyes bájtkódot beolvas, és gépi kódú utasítások sorozataként hajtja végre. Mivel egy megszakítás a gépi kódú utasítások között bármikor bekövetkezhet, az eredeti Python-kódsor lehet, hogy csak részben hajtódott végre. Következésképpen egy a főciklusban módosított Python-objektum, például egy halmaz, lista vagy szótár belső konzisztenciája hiányozhat abban a pillanatban, amikor a megszakítás bekövetkezik.
Egy jellemző kimenetel a következő. Ritka esetekben az ISR pontosan abban a pillanatban fut le, amikor az objektum részben frissített állapotban van. Amikor az ISR megpróbálja beolvasni az objektumot, összeomlás következik be. Mivel az ilyen problémák jellemzően ritkán és lényegében véletlenszerű időpontokban fordulnak elő, nehéz lehet őket diagnosztizálni. Ennek a problémának vannak megkerülési módjai, amelyeket az alábbi Kritikus szakaszok rész ír le.
Fontos tisztában lenni azzal, mi számít egy objektum módosításának. Egy array vagy bytearray tartalmának megváltoztatása biztonságos. Ennek oka, hogy a bájtok vagy szavak egyetlen gépi kódú utasításként íródnak, amely nem megszakítható: a valós idejű programozás szóhasználatában az írás atomi. Ugyanez igaz egy szótárelem frissítésére is, mert az elemek gépi szavak, vagyis egész számok vagy objektumokra mutató pointerek. Egy felhasználó által definiált objektum példányosíthat egy array vagy bytearray objektumot. Mind a főciklus, mind az ISR jogosult ezek tartalmának módosítására.
A veszély akkor merül fel, ha egy objektum szerkezete megváltozik, különösen szótárak esetén. Kulcsok hozzáadása vagy törlése újrahasítást válthat ki. Ha egy hard ISR fut, miközben az újrahasítás folyamatban van, és megpróbál hozzáférni egy elemhez, összeomlás következhet be. Belsőleg a globálisok szótárként vannak megvalósítva. Következésképpen a főprogramnak minden szükséges globálist létre kell hoznia, mielőtt elindít egy hard megszakításokat generáló folyamatot. Az alkalmazáskódnak emellett kerülnie kell a globálisok törlését is.
A MicroPython tetszőleges pontosságú egész számokat támogat. A 230 -1 és -230 közötti értékek egyetlen gépi szóban tárolódnak. A nagyobb értékek Python-objektumként tárolódnak. Következésképpen a hosszú egész számok módosítása nem tekinthető atominak. A hosszú egész számok használata ISR-ekben nem biztonságos, mert a változó értékének változásakor memóriafoglalás kísérelhető meg.
A lebegőpontos korlátozás leküzdése¶
Általában a legjobb elkerülni a lebegőpontos számok használatát az ISR-kódban: a hardvereszközök normál esetben egész számokat kezelnek, és a lebegőpontos számmá alakítás általában a főciklusban történik. Vannak azonban olyan DSP-algoritmusok, amelyek lebegőpontos számokat igényelnek. Hardveres lebegőpontos egységgel rendelkező platformokon (mint például az STM32-alapú OpenMV Cam-ek) a beágyazott ARM Thumb assembler használható e korlátozás megkerülésére. Ez azért van, mert a processzor a lebegőpontos értékeket egy gépi szóban tárolja; az értékek megoszthatók az ISR és a főprogram kódja között egy lebegőpontos tömbön keresztül.
A micropython.schedule használata¶
Ez a függvény lehetővé teszi egy ISR számára, hogy „nagyon hamarosan” történő végrehajtásra ütemezzen egy visszahívást. A visszahívás végrehajtásra kerül a sorba, ami akkor történik meg, amikor a halom nincs zárolva. Így a visszahívás létrehozhat Python-objektumokat és használhat lebegőpontos számokat. A visszahívás futása arra is garantált, hogy akkor történjen, amikor a főprogram befejezte a Python-objektumok bármilyen frissítését, így a visszahívás nem találkozik részben frissített objektumokkal.
Jellemző felhasználása az érzékelő hardver kezelése. Az ISR adatokat olvas be a hardverből, és lehetővé teszi számára, hogy újabb megszakítást váltson ki. Ezután ütemez egy visszahívást az adatok feldolgozására.
Az ütemezett visszahívásoknak meg kell felelniük az alább vázolt megszakításkezelő-tervezési elveknek. Ez azért fontos, hogy elkerüljük az I/O-tevékenységből és a megosztott adatok módosításából eredő problémákat, amelyek bármely olyan kódban felmerülhetnek, amely megelőzi a főprogram ciklusát.
A végrehajtási időt a megszakítások bekövetkezésének gyakoriságához viszonyítva kell figyelembe venni. Ha egy megszakítás akkor következik be, amikor az előző visszahívás éppen fut, a visszahívás egy újabb példánya kerül a sorba végrehajtásra; ez az aktuális példány befejeződése után fut le. Egy tartósan magas megszakítás-ismétlési ráta tehát magában hordozza a korlátlan sornövekedés és végül a RuntimeError hibával történő hiba kockázatát.
Ha a schedule() függvénynek átadandó visszahívás kötött metódus, vedd figyelembe a „Python-objektumok létrehozása” résznél lévő megjegyzést.
Kivételek¶
Ha egy ISR kivételt vált ki, az nem terjed tovább a főciklusba. A megszakítás letiltásra kerül, hacsak az ISR-kód nem kezeli a kivételt.
Csatlakozás az asyncio-hoz¶
Amikor egy ISR fut, megelőzheti az asyncio ütemezőjét. Ha az ISR asyncio-műveletet hajt végre, az ütemező működése megzavarodhat. Ez akkor is érvényes, ha a megszakítás hard vagy soft, és akkor is, ha az ISR a micropython.schedule segítségével adta át a végrehajtást egy másik függvénynek. Különösen a feladatok létrehozása vagy törlése érvénytelen egy ISR-kontextusban. Az asyncio-val való biztonságos kapcsolódás módja egy korutin megvalósítása, ahol a szinkronizálást az asyncio.ThreadSafeFlag végzi. A következő töredék egy feladat megszakítás hatására történő létrehozását szemlélteti:
tsf = asyncio.ThreadSafeFlag()
def isr(_): # Interrupt handler
tsf.set()
async def foo():
while True:
await tsf.wait()
asyncio.create_task(bar())
Ebben a példában változó mértékű késleltetés lesz az ISR végrehajtása és a foo() végrehajtása között. Ez az együttműködő ütemezés velejárója. A maximális késleltetés alkalmazás- és platformfüggő, de jellemzően tíz milliszekundumos nagyságrendben mérhető.
Általános kérdések¶
Ez csupán egy rövid bevezetés a valós idejű programozás témakörébe. A kezdőknek érdemes megjegyezniük, hogy a valós idejű programokban elkövetett tervezési hibák különösen nehezen diagnosztizálható hibákhoz vezethetnek. Ennek oka, hogy ritkán és lényegében véletlenszerű időközönként fordulhatnak elő. Kulcsfontosságú a kezdeti tervezés helyes elvégzése, és a problémák előrelátása még felmerülésük előtt. Mind a megszakításkezelőket, mind a főprogramot az alábbi kérdések figyelembevételével kell megtervezni.
Megszakításkezelők tervezése¶
Ahogy fentebb említettük, az ISR-eket a lehető legegyszerűbbre kell tervezni. Mindig rövid, kiszámítható idő alatt vissza kell térniük. Ez azért fontos, mert amikor az ISR fut, a főciklus nem: a főciklus elkerülhetetlenül szüneteket tapasztal a végrehajtásában a kód véletlenszerű pontjain. Az ilyen szünetek nehezen diagnosztizálható hibák forrásai lehetnek, különösen ha hosszúak vagy változóak. Az ISR futási idejének következményeinek megértéséhez alapvető rálátásra van szükség a megszakítási prioritásokra.
A megszakítások egy prioritási séma szerint vannak rendezve. Magát az ISR-kódot is megszakíthatja egy magasabb prioritású megszakítás. Ennek vannak következményei, ha a két megszakítás adatokat oszt meg (lásd alább a Kritikus szakaszok részt). Ha ilyen megszakítás következik be, az késleltetést iktat be az ISR-kódba. Ha egy alacsonyabb prioritású megszakítás következik be, miközben az ISR fut, az addig késik, amíg az ISR be nem fejeződik: ha a késleltetés túl hosszú, az alacsonyabb prioritású megszakítás meghiúsulhat. A lassú ISR-ek további problémája az az eset, amikor egy második, azonos típusú megszakítás következik be a végrehajtása során. A második megszakítás az első befejeződésekor kerül kezelésre. Ha azonban a beérkező megszakítások üteme tartósan meghaladja az ISR kiszolgálási kapacitását, a végeredmény nem lesz örvendetes.
Következésképpen a ciklusszerkezeteket kerülni vagy minimalizálni kell. A megszakítást okozó eszköztől eltérő eszközökhöz történő I/O-t általában kerülni kell: az olyan I/O, mint a lemezhozzáférés, a print utasítások és az UART-hozzáférés viszonylag lassú, és időtartama változó lehet. További probléma itt, hogy a fájlrendszer-függvények nem újrabelépők: a fájlrendszer-I/O használata egy ISR-ben és a főprogramban veszélyes lenne. Kulcsfontosságú, hogy az ISR-kód ne várjon egy eseményre. Az I/O elfogadható, ha a kód garantáltan kiszámítható időn belül visszatér, például egy láb vagy LED átkapcsolásakor. A megszakítást okozó eszköz I2C vagy SPI útján történő elérése szükséges lehet, de az ilyen hozzáférésekhez szükséges időt ki kell számítani vagy meg kell mérni, és értékelni kell az alkalmazásra gyakorolt hatását.
Általában szükség van az adatok megosztására az ISR és a főciklus között. Ez történhet vagy globális változókon, vagy osztály- illetve példányváltozókon keresztül. A változók jellemzően egész vagy logikai típusúak, vagy egész- vagy bájttömbök (egy előre lefoglalt egésztömb gyorsabb hozzáférést kínál, mint egy lista). Ahol több értéket módosít az ISR, figyelembe kell venni azt az esetet, amikor a megszakítás akkor következik be, amikor a főprogram az értékek némelyikéhez, de nem mindegyikéhez fért hozzá. Ez inkonzisztenciákhoz vezethet.
Vegyük a következő tervet. Egy ISR a beérkező adatokat egy bytearray-ben tárolja, majd a beérkezett bájtok számát hozzáadja egy egész számhoz, amely a feldolgozásra kész bájtok teljes számát jelöli. A főprogram beolvassa a bájtok számát, feldolgozza a bájtokat, majd lenullázza a kész bájtok számát. Ez mindaddig működik, amíg egy megszakítás nem következik be közvetlenül azután, hogy a főprogram beolvasta a bájtok számát. Az ISR a hozzáadott adatokat a pufferbe teszi, és frissíti a beérkezett számot, de a főprogram már beolvasta a számot, így az eredetileg beérkezett adatokat dolgozza fel. Az újonnan beérkezett bájtok elvesznek.
Ennek a veszélynek többféle elkerülési módja van, a legegyszerűbb egy körkörös puffer használata. Ha nem lehetséges egy eleve szálbiztos struktúrát használni, más módokat ismertetünk alább.
Újrabelépés¶
Potenciális veszély merülhet fel, ha egy függvényt vagy metódust megoszt a főprogram és egy vagy több ISR, vagy több ISR egymással. A probléma itt az, hogy magát a függvényt is megszakíthatják, és a függvény egy újabb példánya futhat. Ha ennek elő kell fordulnia, a függvényt újrabelépőre kell tervezni. Hogy ezt hogyan kell megtenni, az egy haladó téma, amely túlmutat ennek az oktatóanyagnak a keretein.
Kritikus szakaszok¶
Egy kód kritikus szakaszára példa az, amely egynél több olyan változóhoz fér hozzá, amelyet egy ISR befolyásolhat. Ha a megszakítás történetesen az egyes változókhoz való hozzáférések között következik be, az értékeik inkonzisztensek lesznek. Ez egy versenyhelyzetnek nevezett veszély egy esete: az ISR és a főprogram ciklusa versenyezve módosítja a változókat. Az inkonzisztencia elkerülése érdekében olyan eszközt kell alkalmazni, amely biztosítja, hogy az ISR a kritikus szakasz időtartama alatt ne módosítsa az értékeket. Ennek egyik módja, ha a szakasz kezdete előtt kiadjuk a machine.disable_irq() hívást, a végén pedig a machine.enable_irq() hívást. Íme egy példa erre a megközelítésre:
import machine
import micropython
import array
import random
import time
micropython.alloc_emergency_exception_buf(100)
class BoundsException(Exception):
pass
ARRAYSIZE = const(20)
index = 0
data = array.array('i', [0] * ARRAYSIZE)
def callback1(t):
global data, index
for x in range(5):
data[index] = random.getrandbits(30) # simulate input
index += 1
if index >= ARRAYSIZE:
raise BoundsException('Array bounds exceeded')
tim = machine.Timer(-1, freq=100, callback=callback1, hard=True)
for loop in range(1000):
if index > 0:
irq_state = machine.disable_irq() # Start of critical section
for x in range(index):
print(data[x])
index = 0
machine.enable_irq(irq_state) # End of critical section
print('loop {}'.format(loop))
time.sleep_ms(1)
tim.deinit()
Egy kritikus szakasz állhat egyetlen sornyi kódból és egyetlen változóból. Vegyük a következő kódtöredéket.
count = 0
def cb(): # An interrupt callback
count += 1
def main():
# Code to set up the interrupt callback omitted
while True:
count += 1
Ez a példa a hibák egy finom forrását szemlélteti. A főciklusban lévő count += 1 sor egy speciális versenyhelyzeti veszélyt hordoz, amelyet olvasás-módosítás-írásnak neveznek. Ez a valós idejű rendszerekben előforduló hibák klasszikus oka. A főciklusban a MicroPython beolvassa a count értékét, hozzáad 1-et, és visszaírja. Ritka esetekben a megszakítás az olvasás után és az írás előtt következik be. A megszakítás módosítja a count értékét, de a változását a főciklus felülírja, amikor az ISR visszatér. Egy valós rendszerben ez ritka, kiszámíthatatlan hibákhoz vezethet.
Ahogy fentebb említettük, óvatosnak kell lenni, ha egy Python beépített típusának egy példányát módosítjuk a fő kódban, és ehhez a példányhoz egy ISR-ben hozzáférünk. A módosítást végző kódot kritikus szakaszként kell kezelni annak biztosítása érdekében, hogy a példány érvényes állapotban legyen, amikor az ISR fut.
Különös gondossággal kell eljárni, ha egy adathalmazt különböző ISR-ek osztanak meg. A veszély itt az, hogy a magasabb prioritású megszakítás akkor következhet be, amikor az alacsonyabb prioritású részben frissítette a megosztott adatokat. Ennek a helyzetnek a kezelése egy haladó téma, amely túlmutat ezen a bevezetésen, azon a megjegyzésen kívül, hogy az alább leírt mutex objektumok néha használhatók.
A megszakítások letiltása a kritikus szakasz időtartamára a szokásos és legegyszerűbb eljárás, de minden megszakítást letilt, nem csupán azt, amely problémát okozhat. Általában nem kívánatos egy megszakítást hosszú időre letiltani. Időzítő-megszakítások esetén ez változékonyságot visz a visszahívás bekövetkezésének idejébe. Eszközmegszakítások esetén oda vezethet, hogy az eszközt túl későn szolgálják ki, ami az eszköz hardverében adatvesztéssel vagy túlcsordulási hibákkal járhat. Az ISR-ekhez hasonlóan a fő kódban lévő kritikus szakasznak is rövid, kiszámítható időtartamúnak kell lennie.
A kritikus szakaszok kezelésének egy megközelítése, amely radikálisan csökkenti azt az időt, ameddig a megszakítások le vannak tiltva, egy mutexnek nevezett objektum használata (a név a kölcsönös kizárás fogalmából származik). A főprogram zárolja a mutexet a kritikus szakasz futtatása előtt, és feloldja a végén. Az ISR megvizsgálja, hogy a mutex zárolva van-e. Ha igen, elkerüli a kritikus szakaszt és visszatér. A tervezési kihívás annak meghatározása, mit tegyen az ISR abban az esetben, ha a kritikus változókhoz való hozzáférést megtagadják. Egy mutex egyszerű példája itt található. Vedd figyelembe, hogy a mutex-kód letiltja a megszakításokat, de csak nyolc gépi utasítás időtartamára: ennek a megközelítésnek az az előnye, hogy más megszakításokat gyakorlatilag nem érint.
Megszakítások és a REPL¶
A megszakításkezelők, például az időzítőkhöz társítottak, egy program befejeződése után is tovább futhatnak. Ez váratlan eredményeket produkálhat, ahol azt várnád, hogy a visszahívást kiváltó objektum már kikerült a hatóköréből. Például egy OpenMV Cam-en:
def bar():
foo = machine.Timer(-1, freq=4, callback=lambda t: print('.', end=''), hard=True)
bar()
Ez addig fut tovább, amíg az időzítőt kifejezetten le nem tiltjuk, vagy a kártyát Ctrl-D paranccsal nem alaphelyzetbe állítjuk.