80

JNI インターフェイス ポインタ (JNIEnv *) は現在のスレッドでのみ有効であることを知りました。ネイティブ メソッド内で新しいスレッドを開始したとします。イベントを Java メソッドに非同期的に送信するにはどうすればよいですか? この新しいスレッドは (JNIEnv *) の参照を持つことができないためです。(JNIEnv *) のグローバル変数を保存してもうまくいかないのですか?

4

2 に答える 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 に答える