NDK学习笔记-JNI多线程
前面讲到记录到ffmpeg音视频解码的时候,采用的是在主线程中进行操作,这样是不行的,在学习了POSIX多线程操作以后,就可以实现其在子线程中解码了,也可以实现音视频同步了
简单示例
在native实现中,直接调用pthread的多线程方法,这样就可以在JNI层实现多线程,下面是一个简单的实现多线程的例子
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <android/log.h>
#include "com_cj5785_posixtest_PosixThread.h"
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO, "cj5785",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR, "cj5785",FORMAT,##__VA_ARGS__);
void* thr_func(void *arg)
{
char *buf = (char *)arg;
int i = 0;
for (i = 0; i < 10; ++i) {
LOGI("thread %s --- %d", buf, i);
if(i == 8)
{
pthread_exit((void *)-1);
}
sleep(1);
}
return (void *)0;
}
JNIEXPORT void JNICALL Java_com_cj5785_posixtest_PosixThread_pthread
(JNIEnv *env, jobject jobj)
{
//创建多线程
pthread_t tid;
pthread_create(&tid, NULL, thr_func, (void *)"thread-0");
}
运行apk发现,主线程并未被阻塞,多线程开启成功
关于JNIEnv与JavaVM
每个线程都会有自己独立的JNIEnv,因此不建议将主线程的
JNIEnv传入到子线程中
而是应该在子线程中获取到自己的JNIEnv在Android中,只有一个
JavaVM对象那么就可以通过
JavaVM获取到每一个线程关联的JNIEnv
在JNI中,有两种方式可以得到JavaVM- 在
JNI_OnLoad函数中获取,JNI_OnLoad在动态库加载时候就会执行,可以在JNI中实现JNI_OnLoad方法,可以得到验证
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){
LOGI("%s","JNI_OnLoad run");
return JNI_VERSION_1_4;
}
(*env)->GetJavaVM(env,&javaVM);,这种方法在创建子线程中调用即可
- 在
在得到
javaVM以后,就可以将javaVM关联当前线程,就可以获取到当前线程的JNIEnv了
(*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
- 在使用完毕以后必须解除关联
(*javaVM)->DetachCurrentThread(javaVM);
注意:这里有一个大坑,JNIEnv不可作为全局变量保存,而应该使用NewGlobalRef()来新建一个全局引用
Native层本地多线程回调Java函数时env->findClass()失败,这里是由于在子线程中不可以找不到类,这个动作需要在主线程中完成
NDK调试
- 首先拿到出错地址,在:
项目/obj/local/armeadi目录下
adb logcat | ndk-stack -sym 链接库地址本地位置
这时候定位到第一个地址,这个地址就是出错地址 - 使用ndk下的编译链工具查找出错的行数
adb logcat | arm-linux-androideabi-addr2line -e 链接库地址本地位置+so
完成以上两步就能够定位出错的位置了
通过JNI拿到Java生成的UUID示例
在Java中生成UUID
import java.util.UUID;
public class UUIDUtils {
public static String getUUID() {
return UUID.randomUUID().toString();
}
}
native方法类中的方法
public native void init();
public native void pthread();
public native void destory();
在native实现中得到UUID值
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <android/log.h>
#include "com_cj5785_posixtest_PosixThread.h"
#define LOGI(FORMAT,...) __android_log_print(4, "cj5785",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT,...) __android_log_print(6, "cj5785",FORMAT,##__VA_ARGS__);
JavaVM *javaVM = NULL;
jclass uuidutils_cls_global = NULL;
jmethodID uuidutils_mid = NULL;
//动态库加载时会执行
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){
LOGI("%s","JNI_OnLoad");
//javaVM = vm;
return JNI_VERSION_1_4;
}
void* thr_func(void *arg)
{
JNIEnv *env = NULL;
//关联
(*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
char *buf = (char *)arg;
int i = 0;
for (i = 0; i < 10; ++i) {
LOGI("%s --- %d", buf, i);
jobject uuid = (*env)->CallStaticObjectMethod(env, uuidutils_cls_global, uuidutils_mid);
const char *uuid_cstr = (*env)->GetStringUTFChars(env, uuid, NULL);
LOGI("%s", uuid_cstr);
(*env)->ReleaseStringUTFChars(env, uuid, uuid_cstr);
}
//解除关联
(*javaVM)->DetachCurrentThread(javaVM);
pthread_exit((void *)0);
}
//初始化
JNIEXPORT void JNICALL Java_com_cj5785_posixtest_PosixThread_init
(JNIEnv *env, jobject jobj)
{
//在主线程中获取class以及methodID
jclass uuidutils_jcls = (*env)->FindClass(env, "com/cj5785/posixtest/UUIDUtils");
uuidutils_cls_global = (*env)->NewGlobalRef(env, uuidutils_jcls);
uuidutils_mid = (*env)->GetStaticMethodID(env, uuidutils_jcls, "getUUID", "()Ljava/lang/String;");
}
JNIEXPORT void JNICALL Java_com_cj5785_posixtest_PosixThread_pthread
(JNIEnv *env, jobject jobj)
{
(*env)->GetJavaVM(env, &javaVM);
//创建多线程
pthread_t tid;
pthread_create(&tid, NULL, thr_func, (void *)"thread-0");
}
//销毁
JNIEXPORT void JNICALL Java_com_cj5785_posixtest_PosixThread_destory
(JNIEnv *env, jobject jobj)
{
(*env)->DeleteGlobalRef(env, uuidutils_cls_global);
}
NDK学习笔记-JNI多线程的更多相关文章
- NDK学习笔记-JNI的引用
JNI中的引用意在告知虚拟机何时回收一个JNI变量 JNI引用变量分为局部引用和全局引用 局部引用 局部引用,通过DeletLocalRef手动释放对象 原因 访问一个很大的Java对象,使用之后还用 ...
- NDK学习笔记-JNI的异常处理与缓存策略
在使用JNI的时候,可能会产生异常,此时就需要对异常进行处理 异常处理 JNI抛出Throwable异常,在Java层可以用Throwable捕捉 而在C只有清空异常这种处理 但如果在JNI中通过Th ...
- NDK学习笔记-JNI数据类型和属性方法的访问
JNI实现了C/C++与Java的相互访问,那么这篇文章就从C/C++访问Java开始说起 native函数说明 每个native函数,都至少有两个参数(JNIEnv *和jclass或jobject ...
- NDK学习笔记-JNI开发流程
JNI(Java Native Interface)Java本地化接口,Java调用C/C++,C/C++调用Java的一套API接口 实现步骤 在Java源文件中编写native方法 public ...
- 孙鑫VC学习笔记:多线程编程
孙鑫VC学习笔记:多线程编程 SkySeraph Dec 11st 2010 HQU Email:zgzhaobo@gmail.com QQ:452728574 Latest Modified ...
- ndk学习20: jni之OnLoad动态注册函数
一.原理 当在系统中调用System.loadLibrary函数时,该函数会找到对应的动态库, 然后首先试图找到"JNI_OnLoad"函数,如果该函数存在,则调用它 JNI_On ...
- android学习笔记----JNI中的c控制java
面向对象的底层实现 java作为面向对象高级语言,可对现实世界进行建模.和面向过程不同的是面向对象软件的编写不是流程的堆积,而是对业务逻辑的多视角分解和分类.其过程大致为: 1).将知识分解 ...
- Android JNI和NDK学习(06)--JNI的数据类型(转)
本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3094037.html 本文介绍JNI的数据类型.NDK中关于JNI数据类型的 ...
- NDK学习笔记-多线程与生产消费模式
在做NDK开发的时候,很多情况下都是需要使用多线程的,一方面是提高程序运行效率,另一方面就是防止主线程阻塞 C的多线程 在C语言里,可以通过对于POSIX标准的运用,使得C语言执行多线程 提高程序的执 ...
随机推荐
- CKEditor5 输入文字时拼音和汉字同时输入问题
在使用 CKEditor5 + vue 时,出现输入文字时,拼音和文字一起输入到编辑器到问题.与之前项目中使用 ckeditor 的区别是,这次项目是在 python 架构下局部引入 ckeditor ...
- linux 批量创建用户
user 模块添加用户 python -c 'from passlib.hash import sha512_crypt; import getpass; print (sha512_crypt.en ...
- 【题解】Mountain Walking-C++
题目题意翻译题意简述:现在给一个N*N的矩阵,找一条路径从左上角走到右下角,每次可以向上下左右四个方向中某个方向走.要求走过的点中,数字最大的减去最小的.要求值越小越好.现在就是要求这个值. 输入格式 ...
- [Luogu P4145] 上帝造题的七分钟2 / 花神游历各国
题目链接 题目简要:我们需要一个能支持区间内每一个数开方以及区间求和的数据结构. 解题思路:说道区间修改区间查询,第一个想到的当然就是分块线段树.数据范围要用long long.本来我是看到区间这两个 ...
- pyecharts 开发文档
pyechart 新 版本 https://pyecharts.org/#/zh-cn/quickstart pyecharts 老版本 https://05x-docs.pyecharts.org/ ...
- GoEasy实现websocket 推送消息通知到客户端
最近在实现一个推送功能,用户扫描二维码签到,后台及时将签到成功信息推送到浏览器端.排除了前端ajax轮询的方式,决定采用websocket及时推送. 于是发现了第三方websocket推送库GoEas ...
- codeforces392B
CF392B Tower of Hanoi 题意翻译 河内塔是一个众所周知的数学难题.它由三根杆和一些可以滑动到任何杆上的不同尺寸的圆盘组成.难题从一个整齐的杆中开始,按照尺寸从小到大的顺序排列,最小 ...
- [svn]查看,删除svn账号
1.查看svn账号 ll ~/.subversion/auth/svn.simple 随便打开一个文件 这是保存的对应地址的svn账号和密码,都是明文的 win路径:C:\Users\ysk\AppD ...
- 调试NTDLL加载
1 随便切到一个进程 0: kd> !process 0 0 explorer.exePROCESS 8157e9a8 SessionId: 0 Cid: 06a4 Peb: 7ffde000 ...
- Quickstart: Create and publish a package using Visual Studio (.NET Framework, Windows)
https://docs.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package-using-visual-studio-n ...