jni多线程问题

chenk818 2012-05-25
jni调用c++代码时,若c++实现里面采用了多线程,则会出现jvm crash的情况,查了一下jni的说明,其中提到:JNIEnv *env指针不可为多个线程共用。但这个说的是env无法在java的各个线程中共用,我遇到的情况是java只有一个线程,而c++实现有多线程,求教。。。
RednaxelaFX 2012-05-25
首先确认一下你确实读到了官方文档:http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html

JNIEnv不能在任意线程中使用。必须是原本就是Java线程(Java代码通过JNI调用native代码时,发起调用的那个肯定是Java线程),或者是让已有的native线程通过JNI来attach到Java环境。
你的每个“C++线程”里都应该要调用AttachCurrentThread()来确保它确实attach到Java环境里了。

jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args);

http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#wp16334
这个函数会通过p_env来返回适合这个通过JNI创建JVM实例的线程使用的JNIEnv。所以你会在各种例子里面看到人家这样写:
JavaVM* jvm = NULL;
JNIEnv* env = NULL;
void* vm_args = ...;
jint res = JNI_CreateJavaVM(&jvm, &env, vm_args);
if (res < 0) {
  // Create JVM failed ...
}

这样调用完之后env就指向了一个可用的JNIEnv。

jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args);

http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#attach_current_thread
同样通过p_env来返回。这是把当前线程(一个已有的native线程)attach到Java环境里。同一个线程反复调用attach不会真的反复attach。

jint AttachCurrentThreadAsDaemon(JavaVM* vm, void** penv, void* args);

http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#attach_current_thread_as_daemon
同上。只是attach的时候指定作为daemon线程来attach。

jint GetEnv(JavaVM *vm, void **env, jint version);

http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#GetEnv
通过JavaVM获取当前线程适用的JNIEnv,通过env返回。如果当前线程没有attach到Java环境里,那么env会被置为NULL,而GetEnv的返回值会是JNI_EDETACHED。
ytulgr 2013-01-16
JAVA多个线程调用C++ Native库方法,C++ Native库中有一个全局变量,多个Java线程是自己加载一个?还是多个线程公用同一个?
RednaxelaFX 2013-01-16
ytulgr 写道
JAVA多个线程调用C++ Native库方法,C++ Native库中有一个全局变量,多个Java线程是自己加载一个?还是多个线程公用同一个?

这种模糊的描述很容易有误差…不过通常这种问题的答案都是“全局变量只有一份,多线程间共用”。
Global site tag (gtag.js) - Google Analytics