JNI インターフェイス ポインタ (JNIEnv *) は現在のスレッドでのみ有効であることを知りました。ネイティブ メソッド内で新しいスレッドを開始したとします。イベントを Java メソッドに非同期的に送信するにはどうすればよいですか? この新しいスレッドは (JNIEnv *) の参照を持つことができないためです。(JNIEnv *) のグローバル変数を保存してもうまくいかないのですか?
67182 次
2 に答える
97
JavaVM*
を使用して、JVM ( )へのポインターを取得できますJNIEnv->GetJavaVM
。そのポインターをグローバル変数として安全に保存できます。後で、新しいスレッドで、AttachCurrentThread
新しいスレッドを C/C++ で作成した場合は新しいスレッドを JVM にアタッチするために使用できます。または、単純に Java コードでスレッドを作成した場合は、JNI がthen をGetEnv
渡すので想定していません。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
于 2012-10-15T17:35:48.250 に答える
86
Java から C++ への JNI を使用した同期呼び出し内では、"環境" は JVM によって既にセットアップされていますが、任意の C++ スレッドから別の方向に進むと、そうではない可能性があります。
したがって、次の手順に従う必要があります
- を使用してJVM環境コンテキストを取得します
GetEnv
- 必要に応じてコンテキストを添付します
AttachCurrentThread
- を使用して通常どおりメソッドを呼び出します
CallVoidMethod
- を使用してデタッチ
DetachCurrentThread
完全な例。これについては、過去にブログで詳しく書いていることに注意してください
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();
}
于 2012-10-15T17:47:39.157 に答える