2017-12-24 25 views
0

私はAndroidからJNI経由で呼び出しているネイティブの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からアクセス可能なモニターがあることがわかりました)。

私はまた非常に頻繁に(OpenGLレンダリングループ中に)呼び出すため、パフォーマンスが重要です。

+0

Javaレベルで「同期」と宣言してください。 – EJP

+0

@ EJPいくつかのメソッドでは、それは十分だと思われますが、場合によっては、メソッド全体を「ロック」する必要はなく、メソッドの一部のみをロックする必要があります。例えば。 'setFoo'では' MyCApiSetFoo'だけをロックできます。その場合、私は何を使うべきですか? –

+0

@MartynPerryあなたの質問にその情報は表示されません。 – EJP

答えて

3

mutexをロックするJNIの方法は、MonitorEnter/MonitorExitです。

つまり、JavaコードからJava​​ブロックと同じモニターを入力できます。

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である必要はありません、ロックオンするために任意のオブジェクトを使用することができます。また

、あなただけのlock_guardで静的std::mutexを使用し、C++コードに構造内部をロックする必要がある場合。