Как реализовать функцию обратного вызова, которая вызывает из Java на C ++?

У меня есть родное приложение C ++, которое создает JVM через JNI, создает экземпляр Java-класса (Akka Actor) и вызывает для него асинхронные неблокирующие функции. Я делаю это, используя JNI в C ++, см. Фрагмент ниже.

Теперь мне нужно получать уведомление в C ++, когда на мой актер Akka приходит ответ Akka. Для этого мне нужно передать указатель на нативную функцию в Java, чтобы актер Java Akka мог вызывать 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";
}

1

Решение

В вашем нативном коде сохраните адрес вашей функции обратного вызова в long. Передайте long вашему Java-коду и сохраните его там как long.

Когда пришло время для обратного вызова, пусть Java передаст адрес функции как long в собственную функцию JNI.

В собственной функции JNI приведите long как указатель на функцию и вызовите его.

1

Другие решения

У меня есть неприятное решение! Вам на самом деле не нужен указатель на встроенную функцию. Актер может просто вызвать собственный метод, который реализован в собственном коде.

Например

class CPPNotifyUtil {

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

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

}

Обратите внимание, что это будет связано с созданием другой нативной библиотеки (противной), на которую ссылается ваше приложение. Это будет точка входа в вашу DLL, но не ваше основное приложение. Вам нужно будет иметь метод в вашей родной dll, который позволяет вам регистрировать списков, чтобы вернуться туда, где вы хотите получать уведомления.

Просто убедитесь, что любой класс, вызывающий нативный метод и ваше основное приложение, находится на одном компьютере. Это касается любого решения.

1