zoukankan      html  css  js  c++  java
  • jni调试3(线程调试env变量问题)

    jni层调试线程死机原因

    一,导致死机原因:

      jni层中  线程函数中  只要添加调用env 的函数 ,,就会死机  
     
    二,解决方法
    第一我们应该理解:
    ①(独立性) JNIEnv 是一个与线程相关的变量,即线程A有一个 JNIEnv变量, 线程B也有一个JNIEnv变量,由于线程相关,所以A线程不能使用B线程的 JNIEnv 结构体变量。那么如何保证了每个线程JNIEnv的独立性呢?
     

    一个java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回,同时把JNI接口的指针JNIEnv *env(虚拟机环境指针),和jobject obj保存在DLL中的变量里.一段时间后,DLL中的消息接收线程接收到服务器发来的消息,并试图通过保存过的env和obj来调用先前的java对象的方法(相当于JAVA回调方法)来处理此消息此时程序会突然退出(崩溃).

    即前台JAVA线程发送消息,后台线程处理消息,归属于两个不同的线程,不能使用相同的JNIEnv变量,这里可以利用一个机制: 利用全局的 JavaVM * 指针得到当前线程的 JNIEnv* 指针,与在C++中两个线程使用TLS进行局部存储类似的原理。


    具体方法:

    获取全局的JavaVM变量:

    /* Our VM */
    JavaVM *g_vm;

    env->GetJavaVM(&g_vm); //来获取JavaVM指针.获取了这个指针后,将该JavaVM保存起来。(转录)

    ②(公共性) 先了解TLS(thread-local storage)

    线程是执行的单元,同一个进程内的多个线程共享了进程的地址空间,线程一般有自己的栈,但是如果想要实现某个全局变量在不同的线程之间取不同的值,而且不受影响。一种办法是采用线程的同步机制,如对这个变量的读写之处加临界区或者互斥量,但是这是以牺牲效率为代价的,能不能不加锁呢?线程局部存储就是干这个的。


     解决以上两个问题:
    1首先定义全局变量
    namespace android
    {
           static JavaVM* gJavaVM  = NULL;  //定义一个全局Java VM引用对象
           static jobject gJavaObj = NULL; //定义一个全局Java object对象,对于java层的类对象
        ......

     2其次在调用某个线程的函数中定义:(保证线程在进程中资源的公共性,这两句是把参数传给所开线程)

    JNIEXPORT void JNICALL Java_Test_setEnev(JNIEnv *env, jobject obj)  
    
    {  
    
        env->GetJavaVM(&gs_jvm); //保存到全局变量中JVM   
    
        //直接赋值obj到DLL中的全局变量是不行的,应该调用以下函数:   
    
        gs_object=env->NewGlobalRef(obj);  
    
      
    
     HANDLE ht=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFun,0,NULL,NULL);  
    
    }
    3在线程函数中 引用:  (保证线程函数 对应  env  和class)
    void WINAPI ThreadFun(PVOID argv)//JNI中线程回调这个方法   
    
    {   
    
     JNIEnv *env;  
    
     gs_jvm->AttachCurrentThread((void **)&env, NULL);    //对应这几句说白了就是从上面函数中把变量取出来在该线程中使用
    
     jclass cls = env->GetObjectClass(gs_object);   //获取JAVA线程中的全局对象
    
     jfieldID fieldPtr = env->GetFieldID(cls,"value","I");   // 获取JAVA对象
    
      
    
     while(1)  
    
     {  
    
        Sleep(100);  
    
       //这里改变JAVA对象的属性值(回调JAVA)   
    
       env->SetIntField(gs_object,fieldPtr,(jint)gs_i++);  
    
      }  
    
    }

     三,我们在网上看到有些关于jni的程序资料用了(*env)->;

    我们需要谨记:在linux下如果.c文件中用 “env->” 编译会找不到此结构,必须用“(*env)->”,或者改成.cpp文件,以 c++的方式来编译。

    ------------------------------------------------------------------------
     
     
     
     
  • 相关阅读:
    [LeetCode] Baseball Game
    [Linux] Shell Scripts
    [Linux] 正则表达式与文件格式化处理
    [Linux] 学习bash
    [Linux] vim程序编辑器
    [Linux] 文件与文件系统的压缩打包与备份
    [LeetCode] Reverse Words in a String
    [LeetCode] Reverse Integer
    [国嵌笔记][017][Makefile工程管理]
    [国嵌笔记][016][交叉工具链]
  • 原文地址:https://www.cnblogs.com/Ph-one/p/4700274.html
Copyright © 2011-2022 走看看