Kérdés a C/C++ nyelv volatile típusminősítéjéről?
Programozzunk C nyelven és Programozzunk C++ nyelven c. könyv:
"A volatile típusminősítővel olyan objektum hozható létre, amelyet (teljesen hivatalosan) a programunktól független kód (például egy másik futó folyamat, vagy megszakítást kezelő rutin) is megváltoztathat."
Ez oké.
"A volatile azt közli a fordítóval, hogy az nem tud mindent, ami az adott objektummal történhet."
Ez is.
"Ezért például a fordító minden egyes, ilyen tulajdonságú objektumra történő hivatkozáskor, a memóriából veszi fel az objektumhoz tartozó értéket."
Két kérdés:
1. Ha volatile változót használok (nyilván futásidőben) akkor hogy kerül a képbe a fordító? Ez nem tiszta
2. Mi az hogy a memóriából veszi fel az értéket? Eleve nem minden változóra történő hivatkozáskor (futásidőben) a program a memóriaterületéről vesz fel értéket, vagy tévednék?
Köszönöm, üdv
A fordító valószínűleg úgy került a képbe, hogy a fordító olyan kódot fordít, ami majd futásidőben a memóriából veszi az értéket. Csak leegyszerűsítették a mondatot. :))
Amikor egy utasítás egy memóriacímre hivatkozik, akkor először a cache-ben (gyorsítótárban) keresi, sőt ha a kód úgy van megírva, akkor a korábbi használat miatt be sem olvassa, mert már valamelyik regiszterben van. Ilyenkor az utasítás az operandust nem a memóriából veszi, mert "közelebb" is rendelkezésre áll. Ez gyorsabb műveletvégzést tesz lehetővé.
Azonban lehetnek olyan memóriarekeszek (pl. objektum változók), amiket "kívülről" más alkalmazás is ír. Ilyenkor hiába van az értéke valamelyik regiszterben, mert taszkváltáskor (mikor visszakerül hozzád a vezérlés) a korábbi, most már rossz értékkel fog számolni a programod. Még rosszabb a helyzet, ha mondjuk egy érzékelő hardverének a memóriájából kell beolvasni valamit, amit a hardver folyamatosan frissít a prpcesszortól függetlenül.
Na, szóval ilyenkor nem elég a korábban feltöltött regiszterekből (vagy külső harder esetén cache-ből) venni az adatot, hanem ki kell nyúlni a memóriába, hogy biztosan azt olvassuk be, amit a másik alkalmazás beleírt.
:)
Ja a lényeg:
Szóval a volatile minősítővel olyan objektm (vagy változó) jön létre, aminek az olvasásakor a fordító olyan kódot generál, ami mindenképpen memóriából olvas, nem egy korábban ugyanonnan feltöltött regiszterből.
(A cache dolgot inkább felejtsd el, amit korábban írtam, mert nem teljesen jó, túlbonyolítottam. A lényeg a regiszterek újtatöltése memóriából.)
Nagyon köszönöm a válaszokat, nagyon hasznosak voltak. Egyetlen kérdés van csak:
A top poster azt írja a fordító optimizálja a kódot. Én azt hittem eddig hogy a fordító sose optimizál, az a programozó feladata. Vagy ez csupán paraméterezés kérdése, pl GCC-nél?
Köszönöm a válaszokat, üdv
Nem olvastam el a linket, de megpróbálok válaszolni.
Valamilyen szintű optimalizálás alapból be szokott lenni kapcsolva. Erre a volatile dologra egy példa:
Mondjuk, hogy van egy 'int i' változód, amihez a fordító (ill. linker) majd hozzárendel egy címet. Amikor kiolvasod a benne lévő értéket, azt a processzor egy regiszterbe tölti az adott memória címről.
Mondjuk, hogy ezután végrehajt pár egyszerű utasítást a proci, és eközben nem nyúl ehhez a regiszterhez. Ezt a fordító tudja. Amikor olvasni akarod az i változót, akkor nem fogja újból beemelni a memóriából, hanem egyből elkezdi használni a korábbi regisztert, hiszen nem nyúlt hozzá, a változót sem írta felül, szóval nyilván ugyanaz az érték van benne. Ezzel nincs is semmi gond, ez egy fajta alap optimalizálás.
A gond akkor kezdődik, ha a változód valamilyen osztott memóriában van, vagy más módon elérhető, és egy másik folyamat vagy szál beleír a változóba. Ezt a fordító előre nem fogja tudni, hiszen taszkváltáskor egy teljesen más kód kezd el futni. Ha ilyen eset lehetséges, akkor érdemes az érintett változókat volatile-vel jelölni, hogy a fordító ott ne optimalizáljon, hanem igenis nyúljon ki a memóriába és töltse be újra a tartalmát.
GCC-nél
-O -O1 -O2
ezek: "optimize for speed" fokozatok
van még, ami méretre optimalizál, de például az IDE-m ben alapból be van jelölve a sebességes,a méret az viszont nincs
Egy konkrétabb példa. Mondjuk van egy kártya a gépben, amiben van egy hőszenzor. A szenzor értékét a kártya egy regiszterében tárolja és folyamatosan frissíti. A regiszterek a memóriában látszanak, adott címtartományban. (Memory mapped device.)
Írsz egy kódot, ahol egymás után többször ellenőrzöd az adott címen lévő szenzor értéket, hogy elért-e egy értéket. A forráskódba beírod, melyik memóriacímről vegye. A fordító össze is rittynet egy gépi kódot hozzá, de látja, hogy ugyanazt a memóriacímed olvasod egymás után, és azt mondja magában, hogy micsoda marhaság, hiszen nem írtunk oda semmit, akkor miért kellene többször a memóriából olvasni? Ezért egy utasítást beszúr, ami beolvassa a memóriából egy regiszterbe, és utána csak onnan veszi az adatokat.
Működés közben csak azt látod, hogy a hőszenzor szerencsétlen írja az adatokat a memóriába, de a programod nem reagál rá, mert rá sem néz. Nem tudja, hogy az értéke megváltozhatott annak ellenére, hogy nem is írt bele új adatot.
Na az ilyen változókat kell volatile szóval jelölni.
:)
Egy x változó akarsz másolni a,b,c változókba.
Ha x nem volatile:
x-et beolvassa AX regiszterbe
AX-et kiírja a-ba
AX-et kiírja b-be
AX-et kiírja c-be
Ha x volatile:
x-et beolvassa AX regiszterbe
AX-et kiírja a-ba
x-et beolvassa AX regiszterbe
AX-et kiírja b-be
x-et beolvassa AX regiszterbe
AX-et kiírja c-be
:)
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!