【问题标题】:JNI Keep Object in C++ alive over multiple JNI callsJNI 通过多个 JNI 调用使 C++ 中的对象保持活动状态
【发布时间】:2016-05-09 14:07:15
【问题描述】:

我的 Java 原生音频库有问题,但首先,这是我目前的方法:

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

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

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

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

所以我搜索了如何使这些对象保持活动状态,并发现可以使用 JNI 进行所谓的“全局引用”。但我不明白它们是否仅适用于 java 对象或两者兼而有之。

我还尝试了另一种 C++ 指针类型是否有帮助。

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

系统信息:

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

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

编辑:

好的,“让猫从后面出来”我正在使用 RtAudio。 Realtime C++ Audio Library

例子:

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

如果我将 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!**  
}

另一个解决方案是在 RtAudio API 中添加一个“keepInstanceAliveThread”,它在 stopStream() 方法之后调用,并在调用 startStream() 或 closeStream() 之后删除。我宁愿选择其他解决方案,但根本没有。

预结果:

感谢@marcinj:

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

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

【问题讨论】:

  • 你知道如何让全局对象在内存中保持活跃吗?即使打开多个活动,我也试图让一个对象保持活动状态。
  • 对不起,我没有发现任何新东西:(
  • 它们用于 Java 对象和类。您也可以考虑弱全局参考。但是audio 到底是什么?它在哪里声明?它是 Java 对象还是 C++ 对象?

标签: java c++ pointers reference java-native-interface


【解决方案1】:

我们可以创建一个新线程来继续在 JNI 函数中运行,其中的变量引用您的对象。

然后单独的调用将停止函数中线程的执行。

////////////////////////////////////

另一种选择是创建对象的全局引用 Android JNI and NewGlobalRef。 在这里,单独调用 USB 断开连接即可DeleteGlobalRef

或通过将 C++ 对象的生命周期传递回 java 层来将其移动到 java 中 keep some sort of c++ object alive over multiple jni calls。 这里单独调用 USB 断开连接将删除 Java 代码中对 C++ 对象的任何引用。

1) 或 2) 中的任何一个的原因都不是,创建的帧然后从堆栈中退出,并且 JNI 本地引用被删除。

当所有 std::thread 引用(理想情况下未分离)被删除时,这将结束 C++ 中的所有线程。在非分离的情况下,std::thread 析构函数在主出口被调用,或者当线程对象超出范围然后调用 terminate() 时。在分离的情况下,分离的线程在应用程序关闭时退出,这会杀死主机进程。

////////////////////////////////////

【讨论】:

    【解决方案2】:

    在 Java 对象中使用 long 来保存指向 C++ 对象的指针。

    Java long 是 64 位的,Java 运行的每个平台都有 32 位或 64 位指针。并且为 Java 提供的每个平台都将支持这一点,尽管它不是严格符合 C 或 C++ 代码。

    Java:

    // class member
    private long audio
    
    // native functions
    private native long openStream( int[] data );
    private native void deleteStream( long audio );
    private native void nativeFillData( long audio, int[] data );
    
    public MyClass()
    {
        audio = openStream( data );
    }
    
    public void fillData( int[] data )
    {
        nativeFillData( this.audio, data );
    }
    
    // delete the C++ object - you may want to
    // control this directly and not rely on
    // finalize() getting called
    protected void finalize()
    {
        deleteStream( audio );
        super.finalize();
    }
    

    C++:

    JNIEXPORT jlong JNICALL openStream(jintArray data)
    {
       RtAudio *audio = new RtAudio(RtAudio::WASAPI);
    
       audio->openStream(&outputParams,....., &callback,....);
       audio->startStream();
    
       // C-style cast - JNI interface is C, not C++
       return( ( jlong ) audio );
    }
    
    JNIEXPORT void JNICALL deleteStream(jlong jaudio)
    {
        RtAudio *audio = static_cast <RtAudio *>( jaudio );
        delete audio;
    }
    
    JNIEXPORT void JNICALL nativeFillData(jlong jaudio, jintArray data)
    {
        RtAudio *audio = static_cast <RtAudio *>( jaudio );
        audio->start();
        ... 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-03
      • 2012-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多