Jadual Kandungan
Pengenalan
Panggil Balik dalam JNA
Aplikasi panggilan balik
Definisi panggil balik
Pemerolehan dan penggunaan panggilan balik
在多线程环境中使用callback
Rumah Java javaTutorial Bagaimana untuk menyelesaikan masalah panggil balik dalam JNA dalam penggunaan java lanjutan

Bagaimana untuk menyelesaikan masalah panggil balik dalam JNA dalam penggunaan java lanjutan

May 05, 2023 am 11:37 AM
java jna

    Pengenalan

    Apakah panggilan balik? Ringkasnya, panggilan balik ialah pemberitahuan panggil balik Apabila kami perlu memberitahu tugasan tertentu selepas kaedah selesai atau peristiwa dicetuskan, kami perlu menggunakan panggilan balik.

    Bahasa yang anda paling mungkin melihat panggilan balik ialah javascript Pada asasnya dalam javascript, panggilan balik ada di mana-mana. Untuk menyelesaikan masalah neraka panggilan balik yang disebabkan oleh panggilan balik, janji telah diperkenalkan khas dalam ES6 untuk menyelesaikan masalah ini.

    Untuk memudahkan interaksi dengan kaedah asli, JNA juga menyediakan Panggilan Balik untuk panggilan balik. Intipati panggilan balik dalam JNA ialah penunjuk kepada fungsi asli Melalui penunjuk ini, kaedah dalam fungsi asli boleh dipanggil.

    Panggil Balik dalam JNA

    Pertama lihat definisi Panggilan Balik dalam JNA:

    public interface Callback {
        interface UncaughtExceptionHandler {
            void uncaughtException(Callback c, Throwable e);
        }
        String METHOD_NAME = "callback";
    
        List<String> FORBIDDEN_NAMES = Collections.unmodifiableList(
                Arrays.asList("hashCode", "equals", "toString"));
    }
    Salin selepas log masuk

    Semua kaedah Panggilan Balik perlu melaksanakan antara muka Panggilan Balik ini. Antara muka Panggilan Balik adalah sangat mudah Ia mentakrifkan antara muka dan dua sifat.

    Mari lihat antara muka ini dahulu Nama antara muka ialah UncaughtExceptionHandler, dan terdapat kaedah uncaughtException di dalamnya. Antara muka ini digunakan terutamanya untuk mengendalikan pengecualian yang tidak ditangkap dalam kod panggil balik JAVA.

    Perhatikan bahawa pengecualian tidak boleh dilemparkan dalam kaedah uncaughtException Sebarang pengecualian yang dilemparkan daripada kaedah ini akan diabaikan.

    METHOD_NAME Medan ini menentukan kaedah untuk dipanggil melalui Panggilan Balik.

    Jika terdapat hanya satu kaedah awam yang ditakrifkan dalam kelas Panggilan Balik, maka kaedah panggil balik lalai ialah kaedah ini. Jika berbilang kaedah awam ditakrifkan dalam kelas Panggilan Balik, kaedah dengan METHOD_NAME = "panggilan balik" akan dipilih sebagai panggilan balik.

    Atribut terakhir ialah FORBIDDEN_NAMES. Menunjukkan bahawa nama dalam senarai ini tidak boleh digunakan sebagai kaedah panggil balik.

    Pada masa ini nampaknya terdapat tiga nama kaedah yang tidak boleh digunakan, iaitu: "hashCode", "equals", dan "toString".

    Panggil balik juga mempunyai adik beradik yang dipanggil DLLCallback Mari kita lihat definisi DLLCallback:

    public interface DLLCallback extends Callback {
        @java.lang.annotation.Native
        int DLL_FPTRS = 16;
    }
    Salin selepas log masuk

    DLLCallback digunakan terutamanya untuk mengakses Windows API.

    Untuk objek panggil balik, kita perlu bertanggungjawab untuk melepaskan objek panggil balik sendiri. Jika kod asli cuba mengakses panggilan balik kitar semula, ia boleh menyebabkan VM ranap.

    Aplikasi panggilan balik

    Definisi panggil balik

    Kerana panggilan balik dalam JNA sebenarnya memetakan penuding kepada fungsi dalam asli. Mula-mula, lihat penuding fungsi yang ditakrifkan dalam struct:

    struct _functions {
      int (*open)(const char*,int);
      int (*close)(int);
    };
    Salin selepas log masuk

    Dalam struktur ini, dua penunjuk fungsi ditakrifkan, dengan dua parameter dan satu parameter masing-masing.

    Takrifan panggil balik JNA yang sepadan adalah seperti berikut:

    public class Functions extends Structure {
      public static interface OpenFunc extends Callback {
        int invoke(String name, int options);
      }
      public static interface CloseFunc extends Callback {
        int invoke(int fd);
      }
      public OpenFunc open;
      public CloseFunc close;
    }
    Salin selepas log masuk

    Kami mentakrifkan dua antara muka dalam Struktur yang diwarisi daripada Panggilan Balik, dan kaedah panggilan yang sepadan ditakrifkan dalam antara muka yang sepadan.

    Kemudian lihat kaedah panggilan khusus:

    Functions funcs = new Functions();
    lib.init(funcs);
    int fd = funcs.open.invoke("myfile", 0);
    funcs.close.invoke(fd);
    Salin selepas log masuk

    Selain itu, Panggilan Balik juga boleh digunakan sebagai nilai pulangan fungsi, seperti ditunjukkan di bawah:

    typedef void (*sig_t)(int);
    sig_t signal(int signal, sig_t sigfunc);
    Salin selepas log masuk

    Untuk penuding fungsi yang berasingan ini, kita perlu menyesuaikan Perpustakaan dan mentakrifkan Panggilan Balik yang sepadan di dalamnya, seperti yang ditunjukkan di bawah:

    public interface CLibrary extends Library {
        public interface SignalFunction extends Callback {
            void invoke(int signal);
        }
        SignalFunction signal(int signal, SignalFunction func);
    }
    Salin selepas log masuk

    Pemerolehan dan penggunaan panggilan balik

    Jika panggilan balik ditakrifkan dalam Struktur, maka ia boleh Structure secara automatik instantiated apabila ia dimulakan, dan kemudian anda hanya perlu mengakses sifat yang sepadan daripada Structure.

    Jika panggilan balik ditakrifkan dalam Perpustakaan biasa, ia adalah seperti berikut:

    public static interface TestLibrary extends Library {
            interface VoidCallback extends Callback {
                void callback();
            }
            interface ByteCallback extends Callback {
                byte callback(byte arg, byte arg2);
            }
            void callVoidCallback(VoidCallback c);
            byte callInt8Callback(ByteCallback c, byte arg, byte arg2);
        }
    Salin selepas log masuk

    Dalam contoh di atas, kami menentukan dua panggilan balik dalam Perpustakaan, satu tanpa panggilan balik nilai pulangan, satu adalah panggilan balik yang mengembalikan bait.

    JNA menyediakan kelas alat mudah untuk membantu kami mendapatkan Panggilan Balik Kelas alat ini ialah CallbackReference, dan kaedah yang sepadan ialah CallbackReference.getCallback, seperti yang ditunjukkan di bawah:

    Pointer p = new Pointer("MultiplyMappedCallback".hashCode());
    Callback cbV1 = CallbackReference.getCallback(TestLibrary.VoidCallback.class, p);
    Callback cbB1 = CallbackReference.getCallback(TestLibrary.ByteCallback.class, p);
    log.info("cbV1:{}",cbV1);
    log.info("cbB1:{}",cbB1);
    Salin selepas log masuk

    Hasil output adalah seperti berikut. :

    INFO com.flydean.CallbackUsage - cbV1:Antara muka proksi ke fungsi asli@0xffffffffc46eeefc (com.flydean.CallbackUsage$TestLibrary$VoidCallback)
    UFO com.Ca.llflybdean c. antara muka ke fungsi asli@0xffffffffc46eeefc (com.flydean.CallbackUsage$TestLibrary$ByteCallback)

    Dapat dilihat bahawa kedua-dua Panggilan Balik ini sebenarnya adalah proksi untuk kaedah asli. Jika anda melihat logik pelaksanaan getCallback secara terperinci:

    private static Callback getCallback(Class<?> type, Pointer p, boolean direct) {
            if (p == null) {
                return null;
            }
            if (!type.isInterface())
                throw new IllegalArgumentException("Callback type must be an interface");
            Map<Callback, CallbackReference> map = direct ? directCallbackMap : callbackMap;
            synchronized(pointerCallbackMap) {
                Reference<Callback>[] array = pointerCallbackMap.get(p);
                Callback cb = getTypeAssignableCallback(type, array);
                if (cb != null) {
                    return cb;
                }
                cb = createCallback(type, p);
                pointerCallbackMap.put(p, addCallbackToArray(cb,array));
                // No CallbackReference for this callback
                map.remove(cb);
                return cb;
            }
        }
    Salin selepas log masuk

    anda boleh melihat bahawa logik pelaksanaannya adalah untuk menentukan terlebih dahulu sama ada jenis itu adalah antara muka Jika ia bukan antara muka, ralat akan dilaporkan. Kemudian tentukan sama ada ia adalah pemetaan langsung. Malah, pelaksanaan semasa JNA adalah semua pemetaan antara muka, jadi logik seterusnya adalah untuk mendapatkan panggilan balik yang sepadan dengan penunjuk fungsi daripada pointerCallbackMap. Kemudian cari Panggilan Balik khusus mengikut jenis yang diluluskan.

    Jika ia tidak ditemui, buat panggilan balik baharu dan akhirnya simpan panggilan balik yang baru dibuat dalam pointerCallbackMap.

    Semua orang harus ambil perhatian bahawa terdapat parameter utama di sini yang dipanggil Penunjuk Apabila benar-benar menggunakannya, anda perlu menghantar penunjuk ke fungsi naitve sebenar. Dalam contoh di atas, demi kesederhanaan, kami menyesuaikan Penunjuk, yang tidak mempunyai banyak kepentingan praktikal.

    如果真的要想在JNA中调用在TestLibrary中创建的两个call方法:callVoidCallback和callInt8Callback,首先需要加载对应的Library:

    TestLibrary lib = Native.load("testlib", TestLibrary.class);
    Salin selepas log masuk

    然后分别创建TestLibrary.VoidCallback和TestLibrary.ByteCallback的实例如下,首先看一下VoidCallback:

    final boolean[] voidCalled = { false };
            TestLibrary.VoidCallback cb1 = new TestLibrary.VoidCallback() {
                @Override
                public void callback() {
                    voidCalled[0] = true;
                }
            };
            lib.callVoidCallback(cb1);
            assertTrue("Callback not called", voidCalled[0]);
    Salin selepas log masuk

    这里我们在callback中将voidCalled的值回写为true表示已经调用了callback方法。

    再看看带返回值的ByteCallback:

    final boolean[] int8Called = {false};
            final byte[] cbArgs = { 0, 0 };
            TestLibrary.ByteCallback cb2 = new TestLibrary.ByteCallback() {
                @Override
                public byte callback(byte arg, byte arg2) {
                    int8Called[0] = true;
                    cbArgs[0] = arg;
                    cbArgs[1] = arg2;
                    return (byte)(arg + arg2);
                }
            };
    
    final byte MAGIC = 0x11;
    byte value = lib.callInt8Callback(cb2, MAGIC, (byte)(MAGIC*2));
    Salin selepas log masuk

    我们直接在callback方法中返回要返回的byte值即可。

    在多线程环境中使用callback

    默认情况下, callback方法是在当前的线程中执行的。如果希望callback方法是在另外的线程中执行,则可以创建一个CallbackThreadInitializer,指定daemon,detach,name,和threadGroup属性:

     final String tname = "VoidCallbackThreaded";
            ThreadGroup testGroup = new ThreadGroup("Thread group for callVoidCallbackThreaded");
            CallbackThreadInitializer init = new CallbackThreadInitializer(true, false, tname, testGroup);
    Salin selepas log masuk

    然后创建callback的实例:

    TestLibrary.VoidCallback cb = new TestLibrary.VoidCallback() {
                @Override
                public void callback() {
                    Thread thread = Thread.currentThread();
                    daemon[0] = thread.isDaemon();
                    name[0] = thread.getName();
                    group[0] = thread.getThreadGroup();
                    t[0] = thread;
                    if (thread.isAlive()) {
                        alive[0] = true;
                    }
                    ++called[0];
                    if (THREAD_DETACH_BUG && called[0] == 2) {
                        Native.detach(true);
                    }
                }
            };
    Salin selepas log masuk

    然后调用:

    Native.setCallbackThreadInitializer(cb, init);
    Salin selepas log masuk

    将callback和CallbackThreadInitializer进行关联。

    最后调用callback方法即可:

    lib.callVoidCallbackThreaded(cb, 2, 2000, "callVoidCallbackThreaded", 0);
    Salin selepas log masuk

    Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan masalah panggil balik dalam JNA dalam penggunaan java lanjutan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Kenyataan Laman Web ini
    Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

    Alat AI Hot

    Undresser.AI Undress

    Undresser.AI Undress

    Apl berkuasa AI untuk mencipta foto bogel yang realistik

    AI Clothes Remover

    AI Clothes Remover

    Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

    Undress AI Tool

    Undress AI Tool

    Gambar buka pakaian secara percuma

    Clothoff.io

    Clothoff.io

    Penyingkiran pakaian AI

    AI Hentai Generator

    AI Hentai Generator

    Menjana ai hentai secara percuma.

    Artikel Panas

    R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
    1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. Tetapan grafik terbaik
    1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
    Akan R.E.P.O. Ada Crossplay?
    1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌

    Alat panas

    Notepad++7.3.1

    Notepad++7.3.1

    Editor kod yang mudah digunakan dan percuma

    SublimeText3 versi Cina

    SublimeText3 versi Cina

    Versi Cina, sangat mudah digunakan

    Hantar Studio 13.0.1

    Hantar Studio 13.0.1

    Persekitaran pembangunan bersepadu PHP yang berkuasa

    Dreamweaver CS6

    Dreamweaver CS6

    Alat pembangunan web visual

    SublimeText3 versi Mac

    SublimeText3 versi Mac

    Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

    Nombor Sempurna di Jawa Nombor Sempurna di Jawa Aug 30, 2024 pm 04:28 PM

    Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

    Weka di Jawa Weka di Jawa Aug 30, 2024 pm 04:28 PM

    Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

    Nombor Smith di Jawa Nombor Smith di Jawa Aug 30, 2024 pm 04:28 PM

    Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

    Soalan Temuduga Java Spring Soalan Temuduga Java Spring Aug 30, 2024 pm 04:29 PM

    Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

    Cuti atau kembali dari Java 8 Stream Foreach? Cuti atau kembali dari Java 8 Stream Foreach? Feb 07, 2025 pm 12:09 PM

    Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

    TimeStamp to Date in Java TimeStamp to Date in Java Aug 30, 2024 pm 04:28 PM

    Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

    Program Java untuk mencari kelantangan kapsul Program Java untuk mencari kelantangan kapsul Feb 07, 2025 am 11:37 AM

    Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

    Bagaimana untuk menjalankan aplikasi boot musim bunga pertama anda di Spring Tool Suite? Bagaimana untuk menjalankan aplikasi boot musim bunga pertama anda di Spring Tool Suite? Feb 07, 2025 pm 12:11 PM

    Spring Boot memudahkan penciptaan aplikasi Java yang mantap, berskala, dan siap pengeluaran, merevolusi pembangunan Java. Pendekatan "Konvensyen Lebih Konfigurasi", yang wujud pada ekosistem musim bunga, meminimumkan persediaan manual, Allo

    See all articles