正确的方式在多线程应用程序使用JNI工作 [英] Right way to work with JNI in multithreading application

查看:236
本文介绍了正确的方式在多线程应用程序使用JNI工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

描述

在我的C ++应用程序类 JNIXMLDocument 这让一些JAVA方法调用。在 JNIXMLDocument 的构造函数I类附着当前线程,并将其设置为我的类成员的JNIEnv * m_JavaEnv ,然后用它在所有的方法。另外在构造函数中,我试图找到我的Java类 COM /菲/安卓/框架/服务/ XMLDOMDocument 键,将其设置为类成员 m_XMLDocumentClass ,也得到了类,类对象并将其设置为类成员 m_XMLDocumentObject

C ++ code

 类JNIXMLDocument
{
    / * **构造函数/
    JNIXMLDocument()
    {
        / *获取JNI正确的版本并进行设置。 ** /
        jint interface_id = JNI_VERSION_1_2;
        #IFDEF JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #其他
            interface_id = JNI_VERSION_1_1;
        #万一        / *试图连接当前线程。 ** /
        INT解析度= g_JavaVirtualMachine-> GETENV(安培; m_JavaEnv,interface_id);
        如果(RES == || JNI_EDETACHED资源== JNI_EVERSION){
            RES = g_JavaVirtualMachine-> AttachCurrentThread(安培; m_JavaEnv,NULL);
        }        / *从Java类获得** /
        m_XMLDocumentClass = m_JavaEnv->的findClass(COM /菲/安卓/框架/服务/ XMLDOMDocument);
        如果(m_XMLDocumentClass!= NULL){
            / *调用Java类的构造函数。 ** /
            jmethodID构造= m_JavaEnv->的GetMethodID(m_XMLDocumentClass,&所述;初始化>中,()V);
            m_XMLDocumentObject = m_JavaEnv-> NewObject的(m_XMLDocumentClass,构造函数);        }    }    布尔初始化()
    {
        jmethodID方法= m_JavaEnv->的GetMethodID(m_XMLDocumentClass,初始化,()Lorg / W3C / DOM /文件;);
        jobject文件= m_JavaEnv-> CallObjectMethod(m_XMLDocumentObject,法);    }    私人的:
        JNIEnv的* m_JavaEnv;
        JCLASS m_XMLDocumentClass;
        jobject m_XMLDocumentObject;
};

C ++ code(正道)

 类JNIXMLDocument
{
    / * **构造函数/
    JNIXMLDocument()
    {
        / *获取JNI正确的版本并进行设置。 ** /
        jint interface_id = JNI_VERSION_1_2;
        #IFDEF JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #其他
            interface_id = JNI_VERSION_1_1;
        #万一        JNIEnv的* ENV;
        / *试图连接当前线程。 ** /
        INT解析度= g_JavaVirtualMachine-> GETENV(安培; ENV,interface_id);
        如果(RES == || JNI_EDETACHED资源== JNI_EVERSION){
            RES = g_JavaVirtualMachine-> AttachCurrentThread(安培; ENV,NULL);
        }        / *从Java类获得** /
        JCLASS localClass = env->的findClass(COM /菲/安卓/框架/服务/ XMLDOMDocument);
        如果(localClass!= NULL){
            m_XMLDocumentClass = env-> NewGlobalRef(localClass);
            / *调用Java类的构造函数。 ** /
            jmethodID构造= env->的GetMethodID(localClass,&所述;初始化>中,()V);
            jobject localObject = env-> NewObject的(m_XMLDocumentClass,构造函数);
            m_XMLDocumentObject = env-> NewGlobalRef(localObject);
        }    }    布尔初始化()
    {    }    私人的:
        JCLASS m_XMLDocumentClass;
        jobject m_XMLDocumentObject;
};

问题


  1. 是不是正确的设置JNI接口指针(的JNIEnv * m_JavaEnv )在构造函数中一次,在整个code使用它?

  2. 是正确设置 JCLASS m_XMLDocumentClass 在构造函数和比使用该变量中的所有方法?

  3. 是正确设置 jobject m_XMLDocumentObject 以这种方式构造 m_JavaEnv-> NewObject的(m_XMLDocumentClass,构造函数); 也许我必须调用 NewGlobalRef

  4. 可以出现什么问题,如果不是在同一个线程我的应用程序的工作(使用多个线程)?


解决方案

  

是不是在构造函数中设置JNI接口指针(JNIEnv的* m_JavaEnv)一次,在整个code使用它?


没有。它是线程特定。这就是附加/ DetachCurrentThread是。这可以工作的唯一方法是,如果C ++对象被创建,并在同一个线程销毁。


  

时的正确设置JCLASS m_XMLDocumentClass在构造函数和比使用该变量中的所有方法?


没有。它是一个本地参考,并且当JNI方法它返回被收购过期。你必须保存为一个全球性或弱引用的除非的它只是将是一个单一的JNI方法中使用。


 是否正确设置jobject m_XMLDocumentObject在构造函数中以这种方式m_JavaEnv-> NewObject的(m_XMLDocumentClass,构造函数);


没有。见上面


  

也许我必须调用NewGlobalRef。


是的,正如上面。


  

有什么问题可以出现,如果在同一个线程我的应用程序不工作(使用多个线程)?


主要是JVM崩溃。在JVM假定您按照JNI规范所有规则。这样做的。

Description

In my C++ application class JNIXMLDocument which made some JAVA method calls. In the constructor of JNIXMLDocument class I attach current thread and set it to my class member JNIEnv* m_JavaEnv and then use it in all methods. Also in the constructor I am trying to find my JAVA class com/fido/android/framework/service/XMLDOMDocument and set it to class member m_XMLDocumentClass and also get that class object from the class and set it to class member m_XMLDocumentObject.

C++ Code

class JNIXMLDocument
{
    /* Constructor **/
    JNIXMLDocument()
    {
        /* Get JNI right version and set it. **/
        jint interface_id = JNI_VERSION_1_2;
        #ifdef JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #else
            interface_id = JNI_VERSION_1_1;
        #endif

        /* Trying to attach current thread. **/
        int res = g_JavaVirtualMachine->GetEnv(&m_JavaEnv, interface_id);
        if (res == JNI_EDETACHED || res == JNI_EVERSION) {
            res = g_JavaVirtualMachine->AttachCurrentThread(&m_JavaEnv, NULL);
        }

        /* Get Class from Java **/
        m_XMLDocumentClass = m_JavaEnv->FindClass("com/fido/android/framework/service/XMLDOMDocument");
        if (m_XMLDocumentClass != NULL) {
            /* Call java class constructor. **/
            jmethodID constructor = m_JavaEnv->GetMethodID(m_XMLDocumentClass , "<init>", "()V");
            m_XMLDocumentObject = m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);    

        }

    }

    bool Initialize()
    {
        jmethodID method = m_JavaEnv->GetMethodID(m_XMLDocumentClass, "Initialize", "()Lorg/w3c/dom/Document;");
        jobject document = m_JavaEnv->CallObjectMethod(m_XMLDocumentObject , method);

    }

    private:
        JNIEnv* m_JavaEnv;
        jclass  m_XMLDocumentClass;
        jobject m_XMLDocumentObject;


};

C++ Code (Right way)

class JNIXMLDocument
{
    /* Constructor **/
    JNIXMLDocument()
    {
        /* Get JNI right version and set it. **/
        jint interface_id = JNI_VERSION_1_2;
        #ifdef JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #else
            interface_id = JNI_VERSION_1_1;
        #endif

        JNIEnv* env;
        /* Trying to attach current thread. **/
        int res = g_JavaVirtualMachine->GetEnv(&env, interface_id);
        if (res == JNI_EDETACHED || res == JNI_EVERSION) {
            res = g_JavaVirtualMachine->AttachCurrentThread(&env, NULL);
        }

        /* Get Class from Java **/
        jclass localClass = env->FindClass("com/fido/android/framework/service/XMLDOMDocument");
        if (localClass != NULL) {
            m_XMLDocumentClass = env->NewGlobalRef(localClass);
            /* Call java class constructor. **/
            jmethodID constructor = env->GetMethodID(localClass, "<init>", "()V");
            jobject localObject = env->NewObject(m_XMLDocumentClass , constructor);    
            m_XMLDocumentObject = env->NewGlobalRef(localObject );
        }

    }

    bool Initialize()
    {

    }

    private:
        jclass  m_XMLDocumentClass;
        jobject m_XMLDocumentObject;


};

Questions

  1. Is it right to set JNI interface pointer (JNIEnv* m_JavaEnv) in the constructor once and use it in the whole code ?
  2. Is it right to set jclass m_XMLDocumentClass in the constructor and than use that variable in the all methods ?
  3. Is it right to set jobject m_XMLDocumentObject in the constructor in this way m_JavaEnv->NewObject(m_XMLDocumentClass , constructor); or maybe I must call NewGlobalRef.
  4. What problems can appear if my application work not in the same thread (use many threads) ?

解决方案

Is it right to set JNI interface pointer (JNIEnv* m_JavaEnv) in the constructor once and use it in the whole code ?

No. It is thread-specific. That's what Attach/DetachCurrentThread are for. The only way this can work is if the C++ object is constructed and destroyed in the same thread.

Is it right to set jclass m_XMLDocumentClass in the constructor and than use that variable in the all methods ?

No. It is a local reference, and it expires when the JNI method it was acquired in returns. You must save as a global or weak reference unless it is only going to be used within a single JNI method.

Is it right to set jobject m_XMLDocumentObject in the constructor in this way m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);

No: see above.

or maybe I must call NewGlobalRef.

Yes, as above.

What problems can appear if my application work not in the same thread (use many threads) ?

Mainly JVM crashes. The JVM assumes you follow all the rules in the JNI specification. So do that.

这篇关于正确的方式在多线程应用程序使用JNI工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆