【发布时间】:2012-10-05 17:25:52
【问题描述】:
了解到JNI接口指针(JNIEnv *)只在当前线程中有效。假设我在本机方法中启动了一个新线程;它如何将事件异步发送到 Java 方法?因为这个新线程不能引用(JNIEnv *)。为 (JNIEnv *) 存储一个全局变量显然不起作用?
【问题讨论】:
标签: java c multithreading java-native-interface
了解到JNI接口指针(JNIEnv *)只在当前线程中有效。假设我在本机方法中启动了一个新线程;它如何将事件异步发送到 Java 方法?因为这个新线程不能引用(JNIEnv *)。为 (JNIEnv *) 存储一个全局变量显然不起作用?
【问题讨论】:
标签: java c multithreading java-native-interface
您可以使用JNIEnv->GetJavaVM 获取指向JVM (JavaVM*) 的指针。您可以安全地将该指针存储为全局变量。稍后,在新线程中,您可以使用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
【讨论】:
AttachCurrentThread的第二个参数如果你不需要任何特殊设置可以为NULL,如果你不需要任何特殊设置,你应该确保在完成后调用DetachCurrentThread附加到开头(否则你会积累无用的 Thread 对象,这些对象永远不会被 GC'd)。
JNIEnv->GetJavaVM接受env作为第一个参数吗?
env 基本上是第一个参数,因为GetJavaVM 是在env 指针上调用的。
在使用 JNI 从 Java 到 C++ 的同步调用中,“环境”已经由 JVM 设置,但是从任意 C++ 线程转到另一个方向,它可能没有设置
因此您需要按照以下步骤操作
GetEnv 获取JVM 环境上下文
AttachCurrentThread附加上下文
CallVoidMethod照常调用该方法
DetachCurrentThread分离
完整示例。请注意,我过去曾在我的blog 上更详细地写过此内容
JavaVM* g_vm;
env->GetJavaVM(&g_vm);
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();
}
【讨论】:
GetEnv、AttachCurrentThread 和DetachCurrentThread,甚至没有解释。