Eseményhurok

A számítástechnikában az eseményhurok [1] [2] [3] , az üzenetküldő , az üzenethurok , az üzenetpumpa vagy a futtatókörnyezet  olyan szoftverkonstrukció, amely várja az érkezést és elosztja az eseményeket vagy üzeneteket a programnak . Úgy működik, hogy kérést küld valamilyen belső vagy külső "eseményszolgáltatónak" (amely általában az esemény bekövetkeztéig blokkolja a kérést), majd meghívja a megfelelő eseménykezelőt ("elküldi az eseményt"). Az eseményhurok a következővel együtt használható egy Reactor tervezési minta , ha az eseményszolgáltató megfelel egy fájlinterfésznek , amely kiválasztható (ami a kiválasztási módszert jelenti) vagy "lekérdezhető" (Unix rendszerhívást jelent, nem tényleges lekérdezést ). Az eseményhurok szinte mindig aszinkron módon fut a feladóval.

Amikor az eseményhurok alkotja a programot alkotó központi vezérlési folyamatot , ahogy ez gyakran megesik, egy ilyen hurkot főhuroknak vagy fő eseményhuroknak nevezhetjük . A név megfelelő, mert egy ilyen eseményhurok a programon belüli vezérlési folyamat legmagasabb szintjén található.

Üzenet átadása

Az üzenetpumpák, ahogy mondani szokták, "pumpálják" a programban lévő üzeneteket az üzenetsorból (melyet csatoltak és általában az operációs rendszer kezel) feldolgozásra. Szigorú értelemben az eseményhurok a folyamatok közötti kommunikáció megvalósításának egyik módja . Valójában sok rendszerben létezik üzenetkezelés, beleértve a Mach operációs rendszer kernel szintjét is . Az eseményhurok egy speciális megvalósítási technika az üzenettovábbítást használó rendszerek számára .

Használat

Hagyományosan a programokat szinkron stílusban írták: a programmal való minden interakció vagy az adatok parancssori argumentumokon keresztül történő átadása vagy felhasználói bevitel volt. Ez a megközelítés alkalmatlannak bizonyult grafikus felületet használó programok írására. Az ilyen programoknál kényelmesebb az aszinkron stílust használni, ahol egy regisztrált kezelő (függvény) hívódik meg bizonyos eseményeknél. Ennek a megközelítésnek a megvalósításához eseményhurkot használnak. Általában az operációs rendszer biztosít egy funkciót a következő üzenet kiválasztásához (pl get_next_message(). , és blokkolja a végrehajtási szálat, amíg legalább egy üzenet meg nem jelenik. Így a ciklustörzs csak akkor fut le, ha van mit feldolgozni. Ha ehhez egy kezelő van regisztrálva Általános szabály, hogy a hosszan tartó műveleteket, például a hálózattal való interakciót más végrehajtási szálakon hajtják végre, hogy a grafikus felület érzékeny maradjon.

Az eseményhurok pszeudokódban :

funkció fő inicializál() miközben üzenet != stop üzenet := get_next_message() process_message(message) end while end függvény


Az aszinkron megközelítés alkalmazásra talált a hálózati programozásban. Például egy aszinkron módon futó, nem blokkoló I/O-t használó nginx szerver sokkal több kapcsolatot képes kezelni, mint a szinkron társai, amelyek kliensenként egy szálat vagy folyamatot hoznak létre.

Megvalósítások

Unix

A Unix rendszerben a „ minden egy fájl ” paradigma természetesen a fájlokhoz kapcsolódó eseményeken alapuló eseményhurokhoz vezet. A fájlok olvasása és írása, a folyamatok közötti kommunikáció, a kommunikációs hálózatok és az eszközkezelés mind fájl I/O használatával érhető el, ahol a fájlokat fájlleírók azonosítják . A rendszerhívások selectés pollszámos fájlleíró állapotának nyomon követését teszi lehetővé, például, hogy megtudja, mikor válik az adatok olvasási/írási állapotba, hibák és egyéb fájlokkal kapcsolatos események. Ezek a hívások blokkolják a program végrehajtását egy bizonyos ideig, amíg a kért esemény meg nem történik az egyik megfigyelt fájlleírón. Ezek a függvények nagyszámú fájlleíróval lelassulnak, így modernebb megfelelőik használatosak: az epoll Linuxon és a kqueue FreeBSD-n. Ezeknek a hívásoknak nem blokkoló fájlleírókat kell használniuk.

Jelfeldolgozás

A Unix azon kevés funkcióinak egyike, amelyek nem felelnek meg a fájlfelületnek, az aszinkron események ( jelek ). A jelkezelőben kapott jelek kicsi, korlátozott kóddarabok, amelyek a feladat többi része felfüggesztése közben futnak. Ha egy jel vétele és feldolgozása történik, és a feladat blokkolva van a -ban select(), akkor az EINTR -velselect() idő előtt leáll . Ha jel érkezik, miközben a kód fut a CPU -n , akkor a feladat felfüggesztésre kerül az utasítások között, amíg a jelkezelő be nem fejezi.

Tehát a jelkezelők számára a jelek kezelésének kézenfekvő módja egy globális jelző beállítása, és ennek a jelzőnek az ellenőrzése az eseményhurokban közvetlenül a hívás előtt és után select(), és ha be van állítva, akkor a jelet ugyanúgy kezelje, mint a leíró eseményeket. . Sajnos ez versenyhelyzethez vezet : ha a zászló ellenőrzése és a hívás között azonnal érkezik egy jel select(), akkor azt nem dolgozzuk fel, amíg select()vissza nem érkezik, vagy valamilyen más okból (például egy frusztrált felhasználó által megszakítva).

A POSIX -ben megérkezett megoldás a pselect , amely hasonló a jelmaszkhoz, select()de van egy további , a jelmaszkotsigmask leíró . Ez lehetővé teszi az alkalmazás számára, hogy maszkolja a jeleket a fő feladatban, majd távolítsa el a maszkot mindaddig, amíg a vezérlés hívásban van , így a jelkezelőket csak akkor hívja meg, ha az alkalmazás I/O határon van . A megvalósítások azonban csak mostanában váltak megbízhatóvá; A Linux 2.6.16 előtti verziók nem tartalmazzák a syscall -t, ami arra kényszeríti a Glibc -et, hogy emulálja azt egy olyan módszerrel, amely ugyanarra a versenyfeltételre hajlamos, mint a . select()pselect() pselect()pselect()

Alternatív és hordozhatóbb megoldás az aszinkron események fájl alapú eseményekké alakítása a pipe-to-self trükk [4] segítségével , amelyben "a jelkezelő egy bájtot ír egy csőbe , amelynek másik végét egy hívás figyeli meg pselect()a fő program". [5] A Linux kernel 2.6.22-es verziójában egy új rendszerhívás került be signalfd(), amely lehetővé teszi a jelek fogadását egy speciális fájlleírón keresztül.

Microsoft Windows

A nem blokkoló I/O mellett, amely olyan I/O multiplexelési funkciókat használ, mint a WSAPoll vagy a select , a Microsoft Windows aszinkron I/O-t is biztosít. Az aszinkron I/O műveletekhez létezik átfedő I/O funkció . Ha a blokkoló függvények, például a ReadFile( ) vagy a WriteFile() átadnak egy struktúrát az egyik argumentumként OVERLAPPED, akkor ezek a függvények azonnal visszaadják a program vezérlését. A művelet befejezéséről a visszahívás funkció vagy az Input/Output completion port ( orosz I/O completion port ) segítségével tájékozódhat.

Az I/O-n kívül a Windows eseményhurokkal is rendelkezik a grafikus alkalmazásokhoz. Az ilyen alkalmazások "szíve" a WinMain() függvény , amely ciklusban hívja meg a GetMessage () függvényt . A GetMessage() blokkol, amíg egy esemény meg nem érkezik (van egy nem blokkoló alternatíva is a PeekMessage() formájában ). Ezután egy kis feldolgozás után a DispatchMessage() meghívásra kerül , amely továbbítja az eseményüzenetet a megfelelő kezelőnek, más néven WindowProc -nak . Azok az üzenetek, amelyekhez nincs regisztrálva kezelő, átadásra kerülnek az alapértelmezett kezelőnek ( DefWindowProc )

Lásd még

Jegyzetek

  1. Retabouil, Sylvain. Android NDK. Alkalmazások fejlesztése Androidra C/C++ nyelven. - M. : DMK Press, 2012. - S. 190. - 496 p. - ISBN 978-5-94074-657-7 .
  2. Budilov Vadim Anatoljevics. Internetes programozás Java nyelven. - Petersburg: BHV, 2003. - S. 41. - 704 p.
  3. Lamothe, André. 3D játékok programozása Windowshoz. 3D grafikai és raszterezési profi tippek (+ CD-ROM) = A 3D-s játékprogramozó guruk trükkjei: Fejlett 3D grafika és raszterezés. - M. : Williams, 2006. - S. 73. - 1415 p. - ISBN 5-8459-0627-X , 0-672-31835-0.
  4. DJ Bernstein. Az öncsöves trükk .
  5. HIBÁK, : szinkron I/O multiplexelés - Linux fejlesztői pselect(2)kézikönyv - rendszerhívások