Program Tip

비동기 호출에 대한 JNI 인터페이스 포인터 (JNIEnv *)를 얻는 방법

programtip 2020. 11. 10. 22:12
반응형

비동기 호출에 대한 JNI 인터페이스 포인터 (JNIEnv *)를 얻는 방법


JNI 인터페이스 포인터 (JNIEnv *)는 현재 스레드에서만 유효하다는 것을 배웠습니다. 네이티브 메서드 내에서 새 스레드를 시작했다고 가정합니다. Java 메소드에 비동기식으로 이벤트를 보내는 방법은 무엇입니까? 이 새 스레드는 (JNIEnv *)에 대한 참조를 가질 수 없습니다. (JNIEnv *)에 대한 전역 변수를 저장하면 분명히 작동하지 않습니까?


Java에서 C ++ 로의 JNI를 사용하는 동기 호출 내에서 "환경"은 이미 JVM에 의해 설정되었지만 임의의 C ++ 스레드에서 다른 방향으로 진행되지 않았을 수 있습니다.

따라서 다음 단계를 따라야합니다.

  • 다음을 사용하여 JVM 환경 컨텍스트를 확보하십시오. GetEnv
  • 필요한 경우 컨텍스트를 첨부하십시오. AttachCurrentThread
  • 다음을 사용하여 정상적으로 메소드를 호출하십시오. CallVoidMethod
  • 사용하여 분리 DetachCurrentThread

전체 예. 참고 나는 과거에 이것에 대해 내 블로그 에 더 자세히 썼습니다.

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*)에 대한 포인터를 얻을 수 있습니다 JNIEnv->GetJavaVM. 해당 포인터를 전역 변수로 안전하게 저장할 수 있습니다. 나중에 새 스레드 AttachCurrentThread에서 새 스레드를 C / C ++로 만든 경우 JVM에 연결하는 데 사용할 수 있습니다. 또는 GetEnvJNI가 JNIEnv*다음을 전달하기 때문에 내가 가정하지 않는 Java 코드로 스레드를 만든 경우 간단히 사용할 수 있습니다. 이 문제는 없을 것입니다.

// 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

참고 URL : https://stackoverflow.com/questions/12900695/how-to-obtain-jni-interface-pointer-jnienv-for-asynchronous-calls

반응형