2017-12-24 30 views
0

JNI를 통해 Android에서 호출 할 원시 C++ 코드가 있습니다.Android JNI - 스레드 동기화

JNIEXPORT void JNICALL 
Java_com_myapp_CApi_setFoo(JNIEnv *env, jobject thiz, jstring foo) { 
    const char * fooStr = env->GetStringUTFChars(foo, 0); 
    MyCApiSetFoo(fooStr); 
    env->ReleaseStringUTFChars(foo, fooStr); 
} 

JNIEXPORT jstring JNICALL 
Java_com_myapp_CApi_getFoo(JNIEnv *env, jobject thiz) { 
    return env->NewStringUTF(MyCApiGetFoo()); 
} 

모두 작동합니다. 그러나 getset 메서드는 다른 스레드에서 액세스 할 수 있으며이 경우 때때로 get이 호출되기 전에 호출됩니다. 스레드 동기화를 어떻게 해결할 수 있습니까? 기본 API를 수정할 수 없습니다.

각 JNI 메서드 내에서 std::unique_lock을 사용하려고 생각하고 잠글 글로벌 변수 std::mutex을 만듭니다. 이것은 좋은 방법인가, 아니면 몇 가지 "표준"JNI 방법이다 (나는 env로부터 accesible 한 모니터가 있다는 것을 발견했다).

나는 또한 매우 자주 (OpenGL 렌더링 루프 동안) 호출하므로 성능이 중요합니다.

+0

Java 수준에서 동기화 된 것으로 선언하십시오. – EJP

+0

@ EJP 일부 방법의 경우에는 충분히 괜찮은 것처럼 보이지만 일부 경우에는 전체 메서드를 "잠글"필요는 없지만 일부 메서드 만 잠글 수 있습니다. 예 : 'setFoo'에서'MyCApiSetFoo' 만 잠글 수 있습니다. 그 경우에는 무엇을 사용해야합니까? –

+0

@MartynPerry 질문에 해당 정보가 없습니다. – EJP

답변

3

뮤텍스를 잠그는 JNI 방법은 MonitorEnter/MonitorExit입니다.

즉, Java 코드에서 Java synchronized 블록과 동일한 모니터를 입력 할 수 있습니다.

JNIEXPORT void JNICALL 
Java_com_myapp_CApi_setFoo(JNIEnv *env, jobject thiz, jstring foo) { 
    const char * fooStr = env->GetStringUTFChars(foo, 0); 
    env->MonitorEnter(thiz); // same effect as synchronized(thiz) { ... 
    MyCApiSetFoo(fooStr); 
    env->MonitorExit(thiz); 
    env->ReleaseStringUTFChars(foo, fooStr); 
} 

JNIEXPORT jstring JNICALL 
Java_com_myapp_CApi_getFoo(JNIEnv *env, jobject thiz) { 
    env->MonitorEnter(thiz); 
    auto res = MyCApiGetFoo(); 
    env->MonitorExit(thiz); 
    return env->NewStringUTF(res); 
} 
당신은에 잠금 개체를 사용할 수 있습니다

, 그것은 그 단위 잠금 충분한 수준을 제공하지 않는 경우 thiz 일 필요는 없습니다. 당신은 단지 구조 C++ 코드 내부을 고정해야하는 경우

또는,하는 lock_guard와 정적 std::mutex를 사용합니다.