Как получить указатель интерфейса JNI (JNIEnv *) для асинхронных вызовов
Я узнал, что указатель интерфейса JNI (JNIEnv *) действителен только в текущем потоке. Предположим, я запустил новый поток внутри собственного метода; как он может асинхронно отправлять события в метод Java? Поскольку этот Новый Поток не может иметь ссылку (JNIEnv *). Хранение глобальной переменной для (JNIEnv *), по-видимому, не будет работать?
2 ответов:
в синхронных вызовах с использованием JNI от Java до C++ "среда" уже настроена JVM, однако в другом направлении от произвольного потока C++ это может быть не
поэтому вам необходимо выполнить следующие действия
- получить доступ к контексту среды JVM с помощью
GetEnv- при необходимости прикрепите контекст с помощью
AttachCurrentThread- вызовите метод как обычно с помощью
CallVoidMethod- отключить используя
DetachCurrentThreadполный пример. Обратите внимание, что я писал об этом в прошлом более подробно на моем блог
void callback(int val) { JNIEnv * g_env; // double check it's all ok int getEnvStat = g_vm->GetEnv((void **)&g_env, JNI_VERSION_1_6); if (getEnvStat == JNI_EDETACHED) { std::cout << "GetEnv: not attached" << std::endl; if (g_vm->AttachCurrentThread((void **) &g_env, NULL) != 0) { std::cout << "Failed to attach" << std::endl; } } else if (getEnvStat == JNI_OK) { // } else if (getEnvStat == JNI_EVERSION) { std::cout << "GetEnv: version not supported" << std::endl; } g_env->CallVoidMethod(g_obj, g_mid, val); if (g_env->ExceptionCheck()) { g_env->ExceptionDescribe(); } g_vm->DetachCurrentThread(); }
вы можете получить указатель на JVM (
JavaVM*) СJNIEnv->GetJavaVM. Вы можете безопасно хранить этот указатель как глобальную переменную. Позже, в новом потоке, вы можете использоватьAttachCurrentThreadчтобы прикрепить новый поток к JVM, если вы создали его в C / C++ или простоGetEnvесли вы создали поток в java-коде, который я не предполагаю, так как JNI передаст вамJNIEnv*тогда и у вас не было бы этой проблемы.// JNIEnv* env; (initialized somewhere else) JavaVM* jvm; env->GetJavaVM(&jvm); // now you can store jvm somewhere // in the new thread: JNIEnv* myNewEnv; JavaVMAttachArgs args; args.version = JNI_VERSION_1_6; // choose your JNI version args.name = NULL; // you might want to give the java thread a name args.group = NULL; // you might want to assign the java thread to a ThreadGroup jvm->AttachCurrentThread((void**)&myNewEnv, &args); // And now you can use myNewEnv
Comments