IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android native开发需要注意native线程的Detach -> 正文阅读

[移动开发]Android native开发需要注意native线程的Detach

前言

如题在跨平台开发的过程中,通常跨平层/C++会创建native线程,如果创建的native线程运行的代码有调用到Java层接口(跟java层有交互),即有调到了AttachCurrentThread,当native线程退出时需要调DetachCurrentThread接口跟JVM世界做分离。否侧会遇到JNI经典崩溃问题之—Native thread exited without calling DetachCurrentThread,如果Deatch的处理逻辑写的不好,可能还会继续遇到JNI经崩溃崩溃问题之—attempting to detach while still running code (这种情况就是java的线程被错误的Detach了!)

解决方案

1.每个线程缓存自己的Env

每个线程缓存自己的Env意味着线程第一个attach到JVM就进行就缓存env实例,待线程退出/销毁时进行deattach操作并置空env实例!实例这个功能需要依赖如下三个接口跟一个线程存储变量/TSD(pthread_key_t变量,变量声名是全局变量,但各个线程会有自己独立的存诸空间)

//创建一个key实例,并绑定key实例释放时的回调函数,即线程退出时会清理所有key,同时调用跟key实例绑定的回调函数!(特别注意这个回调函数,后面会使到它)
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
//保存key实例对应的值,同hashmap的用法
int pthread_setspecific(pthread_key_t key, const void *value);
//获取key对应的值
void *pthread_getspecific(pthread_key_t key);

我们可以参考或抄或拿来主义等等方式使用cocos2d的jni的功能类 cocos2d JinHelperwebtrc的 jvm.cc , JinHelper缓存env的关键实现是getEnv中的cacheEnv函数

    JNIEnv* JniHelper::getEnv() {
         //优先从线程存储的cache中拿
        JNIEnv *_env = (JNIEnv *)pthread_getspecific(g_key);
        if (_env == nullptr)
            _env = JniHelper::cacheEnv(_psJavaVM);
        return _env;
    }

JNIEnv* JniHelper::cacheEnv(JavaVM* jvm) {
        JNIEnv* _env = nullptr;
        // get jni environment
        jint ret = jvm->GetEnv((void**)&_env, JNI_VERSION_1_4);
        
        switch (ret) {
        case JNI_OK :
            // Success! ,已经attch了,就存在线程存储中(这种情况是java调用进来又回调到java层的情况)
            pthread_setspecific(g_key, _env);
            return _env;
                
        case JNI_EDETACHED :
            // Thread not attached, detached的话,再attach一把
            if (jvm->AttachCurrentThread(&_env, nullptr) < 0)
                {
                    LOGE("Failed to get the environment using AttachCurrentThread()");

                    return nullptr;
                } else {
                // Success : Attached and obtained JNIEnv!
                pthread_setspecific(g_key, _env);
                return _env;
            }
                
        case JNI_EVERSION :
            // Cannot recover from this error
            LOGE("JNI interface version 1.4 not supported");
        default :
            LOGE("Failed to get the environment using GetEnv()");
            return nullptr;
        }
    }

  void JniHelper::setJavaVM(JavaVM *javaVM) {
        pthread_t thisthread = pthread_self();
        //LOGD("JniHelper::setJavaVM(%p), pthread_self() = %ld", javaVM, thisthread);
        _psJavaVM = javaVM;
		//绑定key被回收时的回调函数_detachCurrentThread (里边会DetachCurrentThread的方法),从而可以实现线程退出时detach JVM
        pthread_key_create(&g_key, _detachCurrentThread);
    }

void _detachCurrentThread(void* a) {
    cocos2d::JniHelper::getJavaVM()->DetachCurrentThread();
}

2.一次性使用Env

一次性使用Env的意思是,每次attch到JVM获到env并使用env后就deattch JVM。保持attch与eattch的配对!这种方法有点简单但有点暴力!(可能会有性能问题)
示例代码如下

  JNIEnv* env = nullptr;
  int result = g_jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  bool shouldDetach = false;
  if (result == JNI_EDETACHED) {
    jint attachResult = jvm->AttachCurrentThread(&jenv, NULL);
    if (attachResult >= 0)
      shouldDetach = true;
  }
  
  // env的使用,调java的接口接
  ....
  
  if (shouldDetach) {
    g_jvm->DetachCurrentThread();  
  }
  env = nullptr;

参考资料

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-14 14:11:29  更:2021-08-14 14:11:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 1:43:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码