JNI 通过多个 JNI 调用使 C++ 中的对象保持活动状态

the*_*rry 6 c++ java java-native-interface pointers reference

我的 Java 本机音频库有问题,但首先,这是我当前的方法:

  1. 使用本机方法,我打开一个“全局”流,它通过回调函数接收数据。
  2. 回调函数会一直运行,直到没有数据为止。
  3. 如果没有数据,流只会停止,但不会关闭。
  4. 现在我想再次向流提供数据[尝试再次启动流(允许此操作)],但流已被删除。

所以现在我试图弄清楚如何防止从 C++ 或 Java 中删除流。

一种解决方案是在流中创建一个线程,以防止删除。

但我不喜欢这个解决方案......

因此,我搜索了如何使此类对象保持活动状态,并发现可以使用 JNI 进行所谓的“全局引用”。但我不明白它们是只适用于java对象还是两者都适用。

我还尝试了另一种 C++ 指针类型是否可以提供帮助。

我感谢任何帮助或想法,它不一定只是 JNI。C++ 标准库方法/函数/类等也很好:)!

系统信息:

  • 编译器:MinGW64 over MSYS2
  • JDK8u91
  • 当然是64位操作系统(不必命名xD)

全局流意味着所有 JNI 方法都可以访问该流。

编辑:

好吧,“为了让猫从后面出来”,我正在使用 RtAudio。 实时 C++ 音频库

例子:

//THIS IS C++ CODE
RtAudio audio(RtAudio::WASAPI);

int callback(//Buffer stuff etc.){
  //do something
 if(data.isEmpty())return 1;//invokes audio.closeStream() but this does NOT closes the stream!
 else return 0; //Go on with the stream rather wait for the next call
}    


JNIEXPORT void JNICALL openStream(jintArray data){
   //This is a outputstream
   audio.openStream(&outputParams,....., &callback,....);
   audio.startStream();
}

JNIEXPORT void JNICALL fillData(jintArray data){
    //filldata again!
    stream.start(); //Starts the stream but does nothing, because the stream is deleted because of Java 
}
Run Code Online (Sandbox Code Playgroud)

如果我将 openStream 方法更改为此,流将不会被删除,但我正在寻找更好的解决方案......

JNIEXPORT void JNICALL openStream(jintArray data){
   //This is a outputstream
   audio.openStream(&outputParams,....., &callback,....);
   audio.startStream();
 **while(true); //ADD THIS AND THE STREAM WON'T BE DELETED!**  
}
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是在 RtAudio API 中添加一个“keepInstanceAliveThread”,该线程在 stopStream() 方法之后调用,并在调用 startStream() 或 closeStream() 后删除。我宁愿选择另一种解决方案,但目前还没有任何解决方案。

预结果:

感谢@marcinj:

众所周知,全局对象会导致许多问题,很难控制它们的构造/销毁。

编辑:我在互联网上(也在 stackoverflow 上)发现,析构函数是在 JNI 方法返回后调用的。

Moh*_*raj 1

1)JAVA线程方式

\n

我们可以创建一个新线程,以在使用监视器或条件 while 循环锁定的 JNI 函数中保持运行。

\n

然后,单独的调用将通过释放监视器或更改 while 循环中的条件来停止函数中线程的执行。

\n

2)JAVA对象引用方式

\n

另一种选择是创建对象的全局引用\n Android JNI 和 NewGlobalRef。\n这里可以单独调用 USB 断开连接DeleteGlobalRef

\n

我们还可以通过将 C++ 对象传递回 java 层,将其生命周期移至 java\n在多个 jni 调用中保持某种 C++ 对象处于活动状态。\n这里对 USB 断开连接的单独调用将删除对 C++ 对象的任何引用在你的java代码中。

\n

执行

\n

本机文件 (mynative.cpp)

\n
extern "C" JNIEXPORT jobject JNICALL\nJava_com_android_nativecpp_MainActivity_createJniNativeReference(JNIEnv* env, jobject obj, jint size) {\n    void* buf = malloc(size);\n    jobject sharedbytebuffer = env->NewDirectByteBuffer(buf, size);\n    return env->NewGlobalRef(sharedbytebuffer);\n}\n\nextern "C" JNIEXPORT void JNICALL\nJava_com_android_nativecpp_MainActivity_deleteJniNativeReference(JNIEnv* env, jobject obj, jobject sharedbytebuffer) {\n    env->DeleteGlobalRef(sharedbytebuffer);\n    void* buf = env->GetDirectBufferAddress(sharedbytebuffer);        \n    free(buf);\n    return;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Java 文件(MainActivity.java)

\n
import java.nio.ByteBuffer;\n\nprivate ByteBuffer mJniReference;\n\npublic native ByteBuffer createJniNativeReference(int size);\npublic native void deleteJniNativeReference(ByteBuffer mJniReference);\n\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    mJniReference = createJniNativeReference(1000);\n}\n\n\nprotected void onDestroy() {\n    deleteJniNativeReference(mJniReference);\n    super.onDestroy();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

解释

\n

否则,1) 或 2) 的原因是,创建的帧将从堆栈中退出,并删除 JNI 本地引用。

\n

当删除所有\xc2\xa0std::thread 引用\xc2\xa0(理想情况下未分离)时,这将结束 C++ 中的所有线程。\n在非分离情况下,在主函数上调用 std::thread 析构函数。退出,或者当线程对象超出范围然后调用\xc2\xa0terminate() 时。\n在分离的情况下,分离的线程在应用程序关闭时退出,这会杀死主机进程。它们也可以被垃圾收集。

\n