Végrehajtási modell - Execution model

A programozási nyelv egy nyelvtanból/szintaxisból és egy végrehajtási modellből áll . A végrehajtási modell meghatározza a nyelv elemeinek viselkedését. A végrehajtási modell alkalmazásával levezethető egy olyan program viselkedése, amelyet az adott programozási nyelv alapján írtak. Például, amikor egy programozó "elolvassa" a kódot, elméjében végigjárja, hogy mit tesz az egyes kódsorok. Valójában az elméjükben viselkedést szimulálják. A programozó a végrehajtási modellt alkalmazza a kódra, ami a kód viselkedését eredményezi.

Minden egyes programozási nyelv rendelkezik egy végrehajtási modellt, amely meghatározza a módot, ahogyan az egység munkáját (amely jelzi a program szintaktikai ) a tervek szerint a végrehajtás . Néhány népszerű nyelv végrehajtási modelljeinek részletes példái közé tartozik a Python , az Unified Parallel C (UPC) programozási nyelv végrehajtási modellje, a végrehajtási modell különböző osztályainak tárgyalása, például az imperatív és a funkcionális nyelvek esetében. cikk a valós idejű beágyazott nyelvek végrehajtási modelljeit tárgyalja.

A végrehajtási modell részletei

Az operatív szemantika az egyik módszer a nyelv végrehajtási modelljének megadására. A futó program megfigyelt viselkedésének meg kell egyeznie a működési szemantikából (amely a nyelv végrehajtási modelljét határozza meg) származó viselkedéssel.

A végrehajtási modell olyan dolgokra terjed ki, mint ami a munka oszthatatlan egysége, és milyen korlátok korlátozzák a munkaegységek végrehajtásának sorrendjét. Például az összeadási művelet sok nyelven oszthatatlan munkaegység, és a szekvenciális nyelveken az ilyen munkaegységek egymás után történnek.

Ennek illusztrálására tekintsük a C programozási nyelvet , amint azt Kernighan és Richie könyve leírja. C -nek van egy fogalma, amit kijelentésnek neveznek. A nyelvi specifikáció egy utasítást a szintaxis egy részeként definiál, amelyet ";" zár. A nyelvi specifikáció ezt követően azt mondja, hogy "a program végrehajtása egymás után következik". Ezek a szavak: "a program végrehajtása egymás után következik", a C végrehajtási modelljének egy része. Ezek a szavak azt mondják, hogy az állítások oszthatatlan munkaegységek, és hogy ugyanabban a sorrendben haladnak, mint a szintaktikájuk megjelenése a kódban (kivéve, ha egy vezérlő utasítás, például IF vagy FOR módosítja a sorrendet). Azzal a kijelentéssel, hogy "a program végrehajtása egymás után következik", a programozási modell korlátokat fogalmazott meg a munkaegységek végrehajtásának sorrendjében.

A C nyelv valójában egy további szinttel rendelkezik a végrehajtási modellhez képest, ami az elsőbbségi sorrend. Az elsőbbségi sorrend egyetlen utasításon belül tartalmazza a műveleti sorrend szabályait. Az elsőbbségi sorrend úgy tekinthető, mint amely meghatározza az egyetlen utasításon belüli munkaegységek végrehajtásának korlátait. Így, ";" és az "IF" és a "WHILE" a kijelentések sorrendjére vonatkozó korlátozásokat takar, míg az elsőbbségi sorrend a nyilatkozaton belüli munkára vonatkozó korlátozásokat takarja. Ezért a C nyelvi specifikáció ezen részei a C nyelv végrehajtási modelljének részét képezik.

A végrehajtási modellek a programozási nyelvektől függetlenül is létezhetnek, például a POSIX Threads könyvtár és a Hadoop Map-Reduce programozási modellje . A végrehajtási modell végrehajtása fordítón vagy értelmezőn keresztül történhet , és gyakran tartalmaz egy futásidejű rendszert .

Egy végrehajtási modell megvalósítása szabályozza a munka sorrendjét, amelyben a munka a végrehajtás során történik. Ez a sorrend előre kiválasztható, bizonyos helyzetekben, vagy dinamikusan meghatározható a végrehajtás előrehaladtával. A legtöbb végrehajtási modell mindkettőt különböző mértékben engedélyezi. Például a C nyelv rögzíti a munka sorrendjét egy utasításon belül, és rögzíti az összes utasítás sorrendjét, kivéve azokat, amelyek IF utasítást vagy hurok utasítás formát tartalmaznak. Ezért a végrehajtási sorrend nagy részét statikusan, a végrehajtás megkezdése előtt lehet megválasztani, de egy kis részt dinamikusan kell kiválasztani, mivel a végrehajtás folytatódik.

A statikus választásokat leggyakrabban fordítón belül valósítják meg, ilyenkor a munka sorrendjét az utasítások végrehajtható binárisba helyezésének sorrendje jelzi. A dinamikus választásokat ezután a nyelv futásidejű rendszerén belül valósítanák meg . A futásidejű rendszer lehet könyvtár, amelyet a fordító által beszúrt utasítások hívnak meg , vagy a futásidejű rendszer beágyazható közvetlenül a futtatható fájlba, például elágazó utasítások beszúrásával, amelyek dinamikus döntéseket hoznak a következő feladat végrehajtásáról.

Azonban tolmács is elkészíthető bármely nyelvhez, ebben az esetben a végrehajtás sorrendjével kapcsolatos döntések dinamikusak. A tolmácsot részfordítóként és részben végrehajtási modellként tekinthetjük.

Az összeállítási nyelv végrehajtási modellje a mikro-architektúrák általi megvalósítással szemben

Az összeszerelési nyelvek is rendelkeznek végrehajtási modellekkel, ugyanúgy, mint bármely más nyelv. Az ilyen végrehajtási modellt egy CPU mikro-architektúra valósítja meg. Például mind az 5 lépcsős sorrendű folyamat, mind a nagyméretű, soron kívüli CPU ugyanazt az összeállítási nyelvű végrehajtási modellt valósítja meg. A végrehajtási modell a viselkedés definíciója, ezért minden megvalósításnak, legyen az sorrendben vagy soron kívül, vagy értelmezésben vagy JIT-ben stb., Pontosan ugyanazt az eredményt kell adnia, és ezt az eredményt a végrehajtási modell határozza meg .

Párhuzamos végrehajtási modellek

A modern korban a párhuzamos programozás egyre fontosabb téma. A párhuzamos végrehajtási modellek általában bonyolultak, mivel több idővonalat tartalmaznak. A párhuzamos végrehajtási modellek szükségszerűen tartalmazzák a szinkronizációs konstrukciók viselkedését . A szinkronizálási konstrukció azt eredményezi, hogy sorrendet hoz létre az egyik ütemterv tevékenységei között a másik idővonalon végzett tevékenységekhez képest.

Például egy általános szinkronizációs konstrukció a zár. Tekintsünk egy idővonalat. Az idővonalnak van egy pontja, amelyen végrehajtja a "zár tulajdonjogának megszerzése" szinkronizálási konstrukciót. A Posix szálakban ez a pthread_mutex_lock (& ​​myMutex) lenne. Java -ban ez lock.lock () lenne. Mindkét esetben az idővonalat szálnak nevezik. A C és a Java végrehajtási modellek egymást követik, és azt állítják, hogy az idővonalon vannak olyan tevékenységek, amelyek a hívás előtt érkeznek, hogy "megszerezzék a zár tulajdonjogát", és olyan tevékenységek, amelyek a hívás után következnek. Hasonlóképpen van egy "feladja a zár tulajdonjogát" művelet. C -ben ez a pthread_mutex_unlock (& ​​myMutex) lenne. Java -ban ez lock.unlock () lenne. A C és Java végrehajtási modellek ismét meghatározzák, hogy az utasítások egy csoportját a zár tulajdonjogának feladása előtt hajtják végre, és egy másik csoportot a zár tulajdonjogának feladása után.

Nézzük most két idővonal, más néven két szál esetét. Az egyik szál, nevezzük A szálnak, végrehajt néhány utasítást, nevezze őket A-pre-gain-lock utasításoknak. Ezután az A szál végrehajtja a "zár tulajdonjogának megszerzését", majd az A szál végrehajtja az A-post-gain-lock utasításokat, amelyek azután jönnek, hogy A megszerzi a zár tulajdonjogát. Végül az A szál "feladja a zár tulajdonjogát". Ezután az A szál végrehajtja az A-post-giveup-lock utasításokat.

Egy második szál, nevezzük B szálnak, végrehajt néhány utasítást, nevezze őket B-zárolás előtti utasításoknak. Ezután a B szál végrehajtja a "zár tulajdonjogának megszerzését", majd a B szál végrehajtja a zárolás utáni B utasításokat, amelyek azt követően jönnek, hogy B megszerzi a zár tulajdonjogát.

Most azt mondhatjuk, hogy a "nyerjük a zár tulajdonjogát" és a "feladjuk a zár tulajdonjogát" szinkronizálási konstrukció párhuzamos végrehajtási modelljét. A végrehajtási modell a következő:

"Abban az esetben, ha a zár tulajdonjoga az A szálról a B szálra megy át, az A-nyereség-zárás utasítások a B-nyereség-zárás kijelentések elé kerülnek."

És ez az.

Egyszerűnek tűnik, igaz? A bonyodalmak abból fakadnak, hogy a végrehajtási modellnek nincs eszköze a „feladja a zár tulajdonjogát” végrehajtásához, hogy bármiféle befolyása legyen arra, hogy a „zár tulajdonjogának megszerzése” végrehajtása más idővonalon (szál) következik . Nagyon gyakran csak bizonyos átadások adnak érvényes eredményeket. Így a programozónak át kell gondolnia az egyik szál minden lehetséges kombinációját, amely feladja a zárolást, és egy másik szálhoz, amely ezt követi, és meg kell győződnie arról, hogy kódjuk csak érvényes kombinációkat tesz lehetővé.

Ne feledje, hogy az egyetlen hatás az, hogy az A-nyereség-zárolás utasítások a B-nyereség-zárás utasítások előtt vannak. Más hatás nem következik be, és más relatív rendezésre sem lehet támaszkodni. Pontosabban, az A-post-give-up-lock és a B-post-gain-lock nincs meghatározva relatív sorrendben , ami sok embert meglep. De lehet, hogy az A szálat kicserélték a tulajdonjog feladása után, így az A-post-give-up-lock nyilatkozatok jóval azután történhetnek, hogy sok B-gain-lock-utasítás befejeződött. Ez az egyik lehetőség, amelyet figyelembe kell venni a zárak tervezésekor, és illusztrálja, hogy miért nehéz a többszálas programozás.

Vegye figyelembe, hogy a modern párhuzamos nyelvek sokkal könnyebben használhatók végrehajtási modellekkel. A szálmodell az egyik eredeti párhuzamos végrehajtási modell volt, ami megmagyarázhatja, hogy miért maradt fenn annak ellenére, hogy nehéz használni.

Lásd még

Hivatkozások