How to get JNI interface pointer (JNIEnv *) for asynchronous calls

I found out that the JNI interface pointer (JNIEnv *) is only valid in the current thread. Suppose I started a new thread inside my own method; how can it send events to the Java method asynchronously? Since this new thread cannot have a link (JNIEnv *). Saving a global variable for (JNIEnv *) doesn't seem to work?

+51
java c multithreading jni
Oct 15 '12 at 17:15
source share
2 answers

As part of synchronous calls using the JNI from Java to C ++, the "environment" has already been configured by the JVM, however, moving in the other direction from an arbitrary C ++ stream, it may not have been

Therefore, you need to follow these steps

  • Get JVM Environment Context Using GetEnv
  • if necessary, associate the context with AttachCurrentThread
  • call the method as usual using CallVoidMethod
  • detach using DetachCurrentThread

Full example. Note. I wrote about this in the past in more detail on the blog.

 void callback(int val) { JNIEnv * g_env; // double check it 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(); } 
+50
Oct. 15 '12 at 17:47
source share

You can get a pointer to a JVM ( JavaVM* ) with JNIEnv->GetJavaVM . You can safely store this pointer as a global variable. Later in the new thread, you can use AttachCurrentThread to attach the new thread to the JVM if you created it in C / C ++ or just GetEnv if you created the thread in java code, which I do not assume, since the JNI will give you JNIEnv* , and you would not have this problem.

 // 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 
+65
Oct 15 '12 at 17:35
source share



All Articles