java c multithreading jni

java - Cómo obtener el puntero de interfaz JNI(JNIEnv*) para llamadas asincrónicas



multithreading (2)

Aprendí que el puntero de interfaz JNI (JNIEnv *) solo es válido en el hilo actual. Supongamos que comencé un nuevo hilo dentro de un método nativo; ¿Cómo puede enviar eventos de forma asíncrona a un método Java? Como este nuevo hilo no puede tener una referencia de (JNIEnv *). ¿Guardar una variable global para (JNIEnv *) aparentemente no funcionará?


Dentro de llamadas sincrónicas usando JNI de Java a C ++, el "entorno" ya ha sido configurado por la JVM, sin embargo, yendo en la otra dirección desde un hilo de C ++ arbitrario, puede no haber sido

Por lo tanto, debes seguir estos pasos

  • obtener el contexto del entorno JVM usando GetEnv
  • adjunte el contexto si es necesario usando AttachCurrentThread
  • llame al método de forma normal utilizando CallVoidMethod
  • separar usando DetachCurrentThread

Ejemplo completo Tenga en cuenta que he escrito sobre esto en el pasado con más detalle en mi blog

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(); }


Puede obtener un puntero a la JVM ( JavaVM* ) con JNIEnv->GetJavaVM . Puede almacenar ese puntero de forma segura como una variable global. Más tarde, en el nuevo hilo, puede usar AttachCurrentThread para adjuntar el nuevo hilo a la JVM si lo creó en C / C ++ o simplemente GetEnv si creó el hilo en código java que no asumo porque JNI le pasaría una JNIEnv* entonces y no tendrías este problema.

// 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