简体   繁体   中英

How to implement a callback function that calls from Java to C++?

I have a native C++ application that creates a JVM via JNI, instantiates a Java class (an Akka Actor) and invokes asynchronous non-blocking functions on it. I do this using JNI in C++ see snippet below.

Now I need to be notified in C++ when an Akka response arrives to my Akka Actor. For this I need to pass a native function pointer to Java so that the Akka Java Actor can callback to C++ when the response arrives. How can I do that?

Note that using thread synchronization primitives within the Akka Actor would be completely wrong because the Actor would not be able to receive messages if blocked awaiting for some monitor eg a CountDownLatch .

JavaVM* jvm = NULL;
JNIEnv *env = NULL;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=/home/azg/code/hpcmom/target/1.1.9-SNAPSHOT/hpcmom-cmaes/hpcmom-cmaes-1.1.9-SNAPSHOT.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
JNI_GetDefaultJavaVMInitArgs(&vm_args);

// create JVM
JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args);
if (jvm == NULL) {
    throw std::runtime_error("failed creating JVM");
} else {
    log_info << "succeeded creating JVM";
}

// find CmaesClient class
jclass cmaesClass = env->FindClass("com/sfoam/hpcmom/cmaes/CmaesClient");
if (cmaesClass == NULL) {
    throw std::runtime_error("failed finding CmaesClient class");
} else {
    log_info << "succeeded finding CmaesClient class";
}

In your native code, store the address of your callback function in a long. Pass the long to your Java code and store it there, as a long.

When its time for the callback to occur, have Java pass the function's address as a long into a native JNI function.

In the native JNI function, cast the long as a function pointer, and invoke it.

I have a nasty solution! You don't actually need a native function pointer. The actor could just call a method of it's own which is implemented in native code.

For instance

class CPPNotifyUtil {

    static
    {
        System.loadLibrary ("nastylib");
    }

    public native void notifyCPP(); // implement in CPP   

}

Note that would involve creating another native library (nasty) which your application links to. This would then be an entry point into your dll, but not your main application. You would need to have a method in your native dll that allows you to register listiners to get back to where you want to be notified.

Just make sure that any class calling the native method and your main application are located on the same computer. This goes for any solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM