1. ホーム
  2. java

[解決済み] 非同期呼び出しでJNIインターフェースポインタ(JNIEnv *)を取得する方法

2023-07-18 23:58:21

質問

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

どのように解決するには?

Java から C++ への JNI を使用した同期呼び出し内では、quot;環境" はすでに 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();
}