Android JNI - 线程同步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android JNI - 线程同步相关的知识,希望对你有一定的参考价值。

我有一个本机C ++代码,我通过JNI从android调用。

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在set之前被调用。如何解决线程同步问题?我无法编辑底层API。

我在考虑在每个JNI方法中使用std::unique_lock并创建我将锁定的全局std::mutex变量。这是一个好方法,还是有一些“标准”JNI方式(我发现有可以从env访问的监视器)。

我也经常调用get(它是在OpenGL渲染循环期间),因此性能至关重要。

答案

锁定互斥锁的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 ++代码内部的结构,请使用带有std::mutex的静态lock_guard

以上是关于Android JNI - 线程同步的主要内容,如果未能解决你的问题,请参考以下文章

Android jni 线程同步

深入了解android平台的jni---本地多线程调用java代码

如何在android的jni线程中实现回调

Android的JNI调用

Android开发实践:JNI层线程回调Java函数示例

多线程 Thread 线程同步 synchronized