JNI - állapot eltárolása

Fórumok

Üdv!

Remélem vannak itt olyanok, akik komoly tapasztalatokkal rendelkeznek a JNI terén. Bár sok jóra nem számítok, mert már keresgéltem, de nem találtam elfogadható megoldást.

Arra szeretnék valami megoldást találni, hogy egymást követő natív függvényhívások során megőrizzek (illetve továbbadjak) egy, a natív (C) könyvtárra jellemző állapotot reprezentáló objektumot (struktúrát).

Több helyen találkoztam azzal a javaslattal, hogy az adott struktúrára mutató pointert egyszerűen tároljam el a Java objektumomban, egy long típusú mező segítségével, de ez egyértelműen egy agyhalott javaslat. (Semmi sem garantálja, hogy a pointer elfér egy long mezőben.)

Hozzászólások

JNI-hez nem értek, de a long 64 bites Java-ban, milyen pointer nem fér el benne?

Ez egy másik probléma, a két dolgot jelenleg külön kezelem. Mindenesetre az szerintem egy teljesen jogos elvárás, hogy a hordozhatósági szempontból problémás részek kizárólagosan a natív könyvtárakban legyenek, és az ezeket használó Java kóddal ne legyen probléma. (Tudod hogy van: Write once, run anywhere.)

Oracle jvm-en menni fog, meg minden olyan masik jvm-ben amelyiken 64 bites a long, meg minden olyan jvm-ben ahol legalabb 32 bites a long es 32 bites rendszeren futtatod. Azert lassuk be, van kb 50 fele jvm implementacio (amirol en tudok es meg szerintem felszaz olyan amelyikrol nem) es a budos eletbe nem fogod garantalni a java kodod futasat mindegyiken, aligha egy pointer elmentese fogja jelenteni a problemat hordozhatosag szempontjabol.
A java egeszen addig hordozhato, mig a hivatalos megoldast hasznalod (es pont ezert hordozhato, mert a hivatalos megoldast valasztod). Az osszes tobbi jvm-nek verzik valahol a nyaka

// Happy debugging, suckers
#define true (rand() > 10)

Oké, elhiszem, de jelenleg annyi látszik az egészből, hogy 16 éve nem nyúlt hozzá senki.

Arra próbálok kilyukadni, a "long~32bit" azért nagyon durva eltérés a Java spectől. Nem szabadna, hogy annyi JVM-ben előforduljon (igazából egyben sem), hogy erre a fejlesztőnek külön rá kelljen készülni.

Igen, ezért használod a hivatalosat (vagy legalább azt a pár darabot ami legalább nagyban hasonlít rá). Ez egy brutálisan nagy eltérés, viszont ennek ellenére vannak apróságok (nem is egy) amire én utalok (mivel ez volt a mondandóm lényege, hogy a long-ra lehet támaszkodni, mert az a legtöbb jvm-ben adott hogy 64 bit, vagy ha ne adj isten, 32 bit, akkor 32 biten futtatva is jó marad és többet fog szívni a kódhordozás kapcsán a maradék apróságokkal)

// Happy debugging, suckers
#define true (rand() > 10)

Arra bátorkodtam csak reagálni, hogy a "Java csak addig hordozható, amig Oracle VM-et használsz", ami ebben a konkrét esetben nem igaz (és az esetek egy jelentős részében sem), hanem minden JNI specnek megfelelő VM jól fog működni, incl. Dalvik.

A posztolót konkrétan ez érdekelte, csupán őt próbáltam megnyugtatni, nem a te posztodban hibát keresni.

Üdv,
a jófej okoska

En kerek elnezest, valoban kicsit elgordult a gyogyszerem:) Nincs olyan JVM az oracle-s vm-en kivul, amelyik teljesen megfelelne az altaluk adott specnek (vajon miert?:P). Mindegyiknek van baja, kissebb nagyobb, ebbe vagy belefutsz, vagy nem. (altalaban nem, de aki nativ kodot hivogat, az altalaban nem a pointerek elmentesen bukik meg).

// Happy debugging, suckers
#define true (rand() > 10)

Éppen azzal van problémám, hogy szerintem a specifikáció nem garantálja a hordozhatóságot. A long 64 bites, ez rendben van, nem érdekelnek azok a VM-ek, amelyek nem 64 bitesként kezelik ezt a típust, mert azoknak kis túlzással semmi közük a Javához. Azt viszont a specifikáció nem garantálja, hogy az adott architektúra pointer típusa elfér 64 biten. Az persze igaz, hogy az összes elképzelhető jelenleg létező architektúra, amelyen futnia kellene a programnak, 64 bites vagy annál kisebb memóriacímekkel dolgozik.

Ezzel máris megcáfoltad azt az elméletemet, hogy egyelőre nincsenek 128-bites címterű rendszerek. Bocs' mindenkitől.
A másik módszert (byte array) fenntartom -- JNI-ben még nem használtam ilyet, de valami hasonló működött akkor, amikor Oracle-hez csináltam C-ben bővítményt.

Ne aggódj, amíg a te programozói pályád tart, addig a 64-bites long elég lesz egy pointer tárolására.
Ha ebben nem bízol, akkor használj byte-array-t.

PS: a java-s long mindig 64-bites, ez nem platformfüggő (persze ugyanez vonatkozik a JNI-beli 'jlong' típusra is). Ha majd annál nagyobb integer típus lesz Java 1.12-ben, akkor JNI-ben is lesz mód azt használni.

Az egész nagyon korrekten kezelhető, ha csinálsz néhány makrót / inline függvényt ami a natív pointerek tárolását és betöltését intézi a JVM-ből. Azon aggódni most, hogy mi történik, ha 64bitnél nagyobb szószélességű gépen akarod futtatni a programodat, szerintem felesleges. 1001 egyéb dolog van bármilyen nem triviális kódban, amit több értelme van javítani / optimalizálni. A következő 5 évben kicsi az esélye, hogy problémád legyen ebből. Ha lesz, akkor is minimális módosítással kezelni tudod majd.

Természetesen van megoldás arra, hogy bármilyen méretű adatot eltárolj az objektumban, ha egy byte tömböt használsz a long helyett. Ez azonban nagyságrendekkel lassabb lesz, teljesen feleslegesen.

Nekem amikor egyszer jni-n keresztül kellett használni egy rutinkönyvtárat, akkor én csináltam egy köztes (proxy) dll-t, ami az illesztést (típuskonverzió, hibakód->exception, funkcióhívás, normális java api) megcsinálta. Egy dll-nek lehet belső állapota, csak gondolom a multithread működésből adódó problémákra kell figyelni. És akkor C/C++ domain-en belül maradsz, a Java oldal meg csak handle-ken keresztül hivatkozik ezekre.

Az nem játszik, hogy a natív kódban csinálsz egy registryt az ilyen objektumoknak, azaz pointer helyett egy id-t rendelsz hozzájuk, és az az id van megosztva a java-s wrapper osztállyal?

Vagy, egy programozós megoldás: felveszünk a C-részben egy pointer-tömböt, annak az indexeit adjuk a Javának / kapjuk a Javától. A tömböt valamilyen default mérettel foglaljuk (32, pl), amikor betelik, realloc-áljuk kétszeres méretre. A használaton kívüli elemekben vagy NULL-pointer van (ekkor egy szabad elem keresése egy lassú lineáris keresés lesz), vagy egy szabadlistát implementálunk, egy kicsivel több munkával jobb eredményt kapunk.

PS: mindeközben gondolunk arra, hogy thread-safe-en működjünk.

PS2: most látom, más is javasolta már ezt (vagy hasonlót).