1. 程式人生 > >JNI回撥時執行緒安全的處理

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,最

nasty的方式是:

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

int)gettidv1());// 最新的方式

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");