当前位置: 首页 > news >正文

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++的方式来编译。

 

------------------------------------------------------------------------
 
 
 
 

转载于:https://www.cnblogs.com/Ph-one/p/4700274.html

相关文章:

  • 在JNI中新开线程遇到问题
  • 当函数没有return时错误
  • 三星 PMU NXE2000,x-powers的AXP228,NXE2000
  • android-86-Can't create handler inside thread that has not called Looper.prepare()
  • LM393,LM741可以用作电压跟随器吗?
  • android原生系统裁剪
  • 在ubuntu12.04下编译android4.1.2添加JNI层出现问题
  • android学习计划2
  • 1.linux下Kconfig编写规范
  • 2.linux下Makefile编写规范
  • 3.android下Makefile编写规范
  • 4.android.mk编写规范
  • 5.android系统裁剪
  • 2015/08/11博客园页面(自身)
  • 你们都是怎么阅读android系统源码的,用什么工具?
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • exif信息对照
  • javascript从右向左截取指定位数字符的3种方法
  • Kibana配置logstash,报表一体化
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • mysql外键的使用
  • node.js
  • PAT A1092
  • php面试题 汇集2
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 浮动相关
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 汉诺塔算法
  • 记一次删除Git记录中的大文件的过程
  • 简单基于spring的redis配置(单机和集群模式)
  • 批量截取pdf文件
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (+4)2.2UML建模图
  • (1)(1.11) SiK Radio v2(一)
  • (python)数据结构---字典
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • ***监测系统的构建(chkrootkit )
  • .gitignore文件---让git自动忽略指定文件
  • .NET 4.0中的泛型协变和反变
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .net 怎么循环得到数组里的值_关于js数组
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?