永发信息网

如何在JNI中使用线程

答案:2  悬赏:70  手机版
解决时间 2021-03-16 00:01
如何在JNI中使用线程
最佳答案
JNIEnv* g_env;
jobject g_thiz;
JavaVM *g_jvm;
void* thread_get_str(void * argv) {
(g_jvm)->AttachCurrentThread(&g_env, NULL);
LOGE("log in another thread!!!!!!!!!!");
jclass clazz = (g_env)->GetObjectClass(g_thiz);
jfieldID fid = (g_env)->GetFieldID(clazz, "mInstanceName", "Ljava/lang/String;");
jstring jstr = (jstring)(g_env)->GetObjectField(g_thiz, fid);
LOGE("this message is from other thread of c++ %s", (g_env)->GetStringUTFChars(jstr, NULL));
(g_jvm)->DetachCurrentThread();
}

void threadTest(JNIEnv* env, jobject thiz) {
if (g_thiz) {
(g_env)->DeleteGlobalRef(g_thiz);
}
g_thiz = (env)->NewGlobalRef(thiz);
g_env = env;

pthread_t thread;

pthread_create(&thread, NULL, thread_get_str, NULL);

}
看到了么关键是(g_jvm)->AttachCurrentThread(&g_env, NULL); 和(g_jvm)->DetachCurrentThread(); 函数,是把当前的线程绑定到jvm上,我们通过全局变量实现了参数的传递,当然了,其实我们也可以调用AndroidRuntime::getRuntime来获得vm但是比较麻烦,因为有些头文件的配置比较麻烦。至此,我们成功的在c++层使用了线程。

尽管现在中国的工程师还是比较急功近利,总是期望知道是什么,而很少问为什么,但是我觉得一个优秀的工程师应该知道为什么。

首先为什么我们不调用那两个函数就无法使用线程。我的功力有限,简单的看了下,我们JNI函数中的,evn其实是当前线程的环境参数,使用当我们创建新的线程就无法使用了,当我们调用AttachCurrentThread就是为当前线程创建一些环境参数。
1,AttachCurrentThread 调用 attachThread
2, JavaVMAttachArgs argsCopy;
if (args == NULL) {

argsCopy.version = JNI_VERSION_1_2;
argsCopy.name = NULL;
argsCopy.group = (jobject) dvmGetMainThreadGroup();
} else {
assert(args->version >= JNI_VERSION_1_2);

argsCopy.version = args->version;
argsCopy.name = args->name;
if (args->group != NULL) {
argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
} else {
argsCopy.group = (jobject) dvmGetMainThreadGroup();
}
}

bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
这里我们copy了当期的环境参数到新的线程中。
然后接下来就创建线程,然后让线程跑起来。
全部回答
如果你想了解jni在如何在多线程下使用 如果你在子线程使用jni时遇到findclass不能找到目标class,而在主线程下却能找到该class的问题。或是getenv返回null的问题 如果你想多学点编程技术的话 那么,这篇文章就是为你而写的, :) 最近工作中遇到这么个问题:c++代码需要调用android的api来做一个比较耗时的任务,因为有点耗时,希望能有个进度条显示给用户,很自然地,我创建了一个子线程用来执行这个耗时的任务,按照平时写法,结果一运行,getenv获取失败了。网上查找一番,官方说明有这么句话: if the current thread is not attached to the vm, sets *env to null, and returns jni_edetached. if the specified version is not supported, sets *env to null, and returns jni_eversion. otherwise, sets *env to the appropriate interface, and returns jni_ok. 调试后找到了原因,the current thread is not attached。 原来子线程函数里需要使用attachcurrentthread()和detachcurrentthread()这两个函数。没错,你需要gjvm->attachcurrentthread(&env, null);来获取env,这样写之后,以为万事大吉了,结果findclass出错了,没有找到目标类,可是我千真万确地记得在主线程里这么写是没有问题的。env没有问题了,这回又哪里出错了呢?上网google一番,噢,不对,google被墙了,是用bing查找一番后,总算有些眉目了。 首先确保你的class name写对了,以包名开头,并用反斜杠隔开。如果class name没有错,那么应该是class loader的问题了。解决方法是你先在主线程中获取该class,并且将其保存为全局变量,以便其他线程使用。 jclass tmp = env->findclass("com/example/company/myclass"); myclass = (jclass)env->newglobalref(tmp); 在子线程中, mid = env->getstaticmethodid(cls, "fromjni", "(i)v"); if (mid != null) { env->callstaticvoidmethod(env, cls, mid, i); } 当然,也有其他解决方法,至少我使用这种方法成功了。而接下来在java中调用c++的代码就比较顺利了,木有碰到问题了。 总结: 1.在jni_onload中,保存javavm*,这是跨线程的,持久有效的,而jnienv*则是当前线程有效的。一旦启动线程,用attachcurrentthread方法获得env。 2.通过javavm*和jnienv可以查找到jclass。 3.把jclass转成全局引用,使其跨线程。 4.然后就可以正常地调用你想调用的方法了。 5.用完后,别忘了delete掉创建的全局引用和调用detachcurrentthread方法。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
临沭县白旄镇的马蹄泉具体在什么地方啊
性格早熟好吗?拜托各位大神
腾讯大王卡或者腾讯帝王卡能玩火柴人联盟二吗
冒险岛二区祖母绿的暗器伤人20多少钱一本
考研来讲南京农业大学机械是不是可以一考
我的快易典学习机很长时间没用开不了机怎么办
ogawa在什么地方啊,我要过去处理事情
如何把抠出的图保存
泰安离济南长清多远?
农村5月为什么有不让剪头发之说
今天刚买的索泰gtx1060 6g 运行守望先锋60fps
清末民初的手镯真的值几十万吗,银手镯
charlotte男主第几集知道自己的能力
Psyche.Q买手店我想知道这个在什么地方
里约奥运会女子山地车比赛距离
推荐资讯
如果明天早上,你突然发现变了性别。你的第一
农民工养老保险减少表格如何填写,单位编号和
荣耀6手机如何设置群组个性铃声
青山村村民委员会这个地址在什么地方,我要处
歌词有 晕眩眩 晕眩眩 的日本歌叫什么
王者荣耀哪些英雄是攻速暴击
顺昌物流怎么去啊,有知道地址的么
绵阳平政车站到双流机场的班车是停在哪个航站
彩香洗化地址在哪,我要去那里办事,
昆明的核桃批发市场在哪里
来电显示有些带有 86,有的不带?
公积金贷款十万十年还齐月供多少
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?