JNIインターフェイスポインター(JNIEnv *)は現在のスレッドでのみ有効であることを学びました。ネイティブメソッド内で新しいスレッドを開始したとします。非同期にイベントをJavaメソッドに送信できますか?この新しいスレッドは(JNIEnv *)の参照を持つことができません。
JavaからC++へのJNIを使用する同期呼び出し内で、「環境」はすでにJVMによってセットアップされていますが、任意のC++スレッドから他の方向に進むことはできませんでした。
したがって、次の手順に従う必要があります
GetEnv
を使用してJVM環境コンテキストを取得しますAttachCurrentThread
を使用してコンテキストを添付しますCallVoidMethod
を使用して通常どおりメソッドを呼び出しますDetachCurrentThread
を使用してデタッチします完全な例。注:これについては、過去に詳細に 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();
}
JVMへのポインターを取得できます(JavaVM*
)with JNIEnv->GetJavaVM
。そのポインターをグローバル変数として安全に保存できます。後で、新しいスレッドで AttachCurrentThread
を使用して、新しいスレッドをC/C++で作成した場合はJVMにアタッチするか、単に 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