JNI回撥時執行緒安全的處理
在網上能找到有關
“在Jni中通過 env->CallStaticVoidMethod去做callback的時候,總會掛掉 原因是JniEnv是和執行緒相關的,只能在對應建立的執行緒中使用 而JVM卻是程序相關的,可以通過JVM來獲取執行緒相關的JNIENV。”
關於這個的解決辦法,能搜到的都基本一模一樣。變數名都不帶改的。
基本都是通過
fields.pjvm->AttachCurrentThread(&env, NULL); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg); Fields.pjvm->DetachCurrentThread();
這種方式來解決執行緒問題。
今天偶然發現一種挺好的方式:
JNIEXPORT jint JNICALL Reset
(JNIEnv *env, jclass cls)
{
SET_ENV(env);
.....
}
void SET_ENV(JNIEnv* env)
{
pid_t tid = syscall(__NR_gettid); // current thread id
g_JNIENV_Map[tid] = env;
}
下面這部分是抄來的
//system call number:
#define __NR_gettid 224
因此,要獲取某個執行緒的TID,最
1. #include <sys/syscall.h>
2. printf("The ID of this thread is: %ld\n", (longint)syscall(224));
或者比較elegant的方式是:
1. #include <sys/syscall.h>
2. #define gettidv1() syscall(__NR_gettid)
3. #define gettidv2() syscall(SYS_gettid)
4. printf("The ID of this thread is: %ld\n", (long
5. printf("The ID of this thread is: %ld\n", (longint)gettidv2());// traditional form
PS: 在/usr/include/sys/syscall.h中可以看到關於__NR_<name>和SYS_<name>兩個巨集的區別,實際最後使用的都是__NR_<name>。
就是為了證明這程式碼是獲取當前執行緒ID的(Linux)
pid_t tid = syscall(__NR_gettid); // current thread id
JNIEnv* GET_ENV()
{
pid_t tid = syscall(__NR_gettid); // current thread id
map<pid_t, JNIEnv*>::iterator it = g_JNIENV_Map.find(tid);
if (it == g_JNIENV_Map.end())
{
return NULL;
}
else
{
return it->second;
}
}
這樣,你在需要使用env的時候就能根據當前執行緒找到對應的正確的env指標了。
JNIEnv *env = GET_ENV();
jclass cls = env->FindClass(XXX);
jmethodID methodId =
env->GetStaticMethodID(cls, "showDialog", "()V");