如何实现从Java调用C ++的回调函数?

时间:2014-02-20 16:55:26

标签: java c++ callback java-native-interface akka

我有一个本机C ++应用程序,它通过JNI创建一个JVM,实例化一个Java类(一个Akka Actor)并在其上调用异步非阻塞函数。我在C ++中使用JNI执行此操作,请参阅下面的代码段。

现在,当Akka回复到达我的Akka Actor时,我需要在C ++中得到通知。为此,我需要将一个本机函数指针传递给Java,以便Akka Java Actor可以在响应到达时回调到C ++。我怎样才能做到这一点?

请注意,在Akka Actor中使用线程同步原语是完全错误的,因为如果阻塞等待某个监视器,则Actor将无法接收消息,例如一个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";
}

2 个答案:

答案 0 :(得分:1)

在您的本机代码中,将回调函数的地址存储为long。将long传递给Java代码并将其存储在那里,很长一段时间。

当回调发生的时候,让Java将函数的地址作为long传递给本机JNI函数。

在本机JNI函数中,将long转换为函数指针,然后调用它。

答案 1 :(得分:1)

我有一个讨厌的解决方案!您实际上并不需要本机函数指针。演员可以调用它自己的方法,用本机代码实现。

例如

class CPPNotifyUtil {

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

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

}

请注意,这将涉及创建应用程序链接到的另一个本机库(讨厌)。这将是您的dll的入口点,但不是您的主要应用程序。您需要在本机dll中使用一种方法,允许您注册列表器以返回到您希望收到通知的位置。

确保调用本机方法的任何类和主应用程序位于同一台计算机上。这适用于任何解决方案。