Как получить указатель интерфейса JNI (JNIEnv *) для асинхронных вызовов



Я узнал, что указатель интерфейса JNI (JNIEnv *) действителен только в текущем потоке. Предположим, я запустил новый поток внутри собственного метода; как он может асинхронно отправлять события в метод Java? Поскольку этот Новый Поток не может иметь ссылку (JNIEnv *). Хранение глобальной переменной для (JNIEnv *), по-видимому, не будет работать?

708   2  

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

    Ничего не найдено.