Multithreading JNI:从线程崩溃调用CallVoidMethod
出于某种原因,当我试图从线程访问java对象(顺便说一句,它贯穿整个程序)时,程序崩溃了。下面是一个简要的示例来说明问题:Multithreading JNI:从线程崩溃调用CallVoidMethod,multithreading,java-native-interface,Multithreading,Java Native Interface,出于某种原因,当我试图从线程访问java对象(顺便说一句,它贯穿整个程序)时,程序崩溃了。下面是一个简要的示例来说明问题: #include <jni.h> #include <pthread.h> pthread_t thread; jobject object; JavaVM* jvm; /* Our thread function: */ void* run( void* ); extern "C" void Java_com_Program_Initial
#include <jni.h>
#include <pthread.h>
pthread_t thread;
jobject object;
JavaVM* jvm;
/*
Our thread function:
*/
void* run( void* );
extern "C" void Java_com_Program_Initialize( JNIEnv* jnv, jobject caller )
{
object = caller;
jnv->GetJavaVM( &jvm );
/*
Before launching our thread, this works just fine:
*/
jnv->CallVoidMethod( object, jnv->GetMethodID( jnv->GetObjectClass( object ), "foo", "()V" ) );
pthread_create( &thread, NULL, run, NULL );
}
void* run( void* )
{
JNIEnv* jnv;
jvm->AttachCurrentThread( &jnv, NULL );
/*
Within the context of our thread however, this crashes:
*/
jnv->CallVoidMethod( object, jnv->GetMethodID( jnv->GetObjectClass( object ), "foo", "()V" ) );
jvm->DetachCurrentThread( );
return NULL;
}
#包括
#包括
pthread\u t线程;
作业对象;
JavaVM*jvm;
/*
我们的线程函数:
*/
无效*运行(无效*);
外部“C”无效Java\u com\u程序\u初始化(JNIEnv*jnv,jobject调用者)
{
对象=调用方;
jnv->GetJavaVM(&jvm);
/*
在启动我们的线程之前,这一切正常:
*/
jnv->CallVoidMethod(对象,jnv->GetMethodID(jnv->GetObjectClass(对象),“foo”,以及“()V”);
pthread_创建(&thread,NULL,run,NULL);
}
void*运行(void*)
{
JNIEnv*jnv;
jvm->AttachCurrentThread(&jnv,NULL);
/*
但是,在我们的线程上下文中,这会崩溃:
*/
jnv->CallVoidMethod(对象,jnv->GetMethodID(jnv->GetObjectClass(对象),“foo”,以及“()V”);
jvm->DetachCurrentThread();
返回NULL;
}
有什么问题吗?好的,问题似乎是缺少一个新的GlobalRef呼叫。此版本适用于:
#include <jni.h>
#include <pthread.h>
pthread_t thread;
jobject object;
JavaVM* jvm;
/*
Our thread function:
*/
void* run( void* );
extern "C" void Java_com_Program_Initialize( JNIEnv* jnv, jobject caller )
{
object = jnv->NewGlobalRef( caller );
jnv->GetJavaVM( &jvm );
pthread_create( &thread, NULL, run, NULL );
}
void* run( void* )
{
JNIEnv* jnv;
jvm->AttachCurrentThread( &jnv, NULL );
jnv->CallVoidMethod( object, jnv->GetMethodID( jnv->GetObjectClass( object ), "foo", "()V" ) );
jnv->DeleteGlobalRef( object );
jvm->DetachCurrentThread( );
return NULL;
}
#包括
#包括
pthread\u t线程;
作业对象;
JavaVM*jvm;
/*
我们的线程函数:
*/
无效*运行(无效*);
外部“C”无效Java\u com\u程序\u初始化(JNIEnv*jnv,jobject调用者)
{
object=jnv->NewGlobalRef(调用者);
jnv->GetJavaVM(&jvm);
pthread_创建(&thread,NULL,run,NULL);
}
void*运行(void*)
{
JNIEnv*jnv;
jvm->AttachCurrentThread(&jnv,NULL);
jnv->CallVoidMethod(对象,jnv->GetMethodID(jnv->GetObjectClass(对象),“foo”,以及“()V”);
jnv->DeleteGlobalRef(对象);
jvm->DetachCurrentThread();
返回NULL;
}
我建议您尝试找到一种将调用发布到主线程的方法
由于从“AttachCurrentThread”到“DetachCurrentThread”的整个过程未锁定,因此在某些情况下,在“run”完成之前,主线程可能会重新“AttachCurrentThread”。因此仍然会有问题。最好将对象作为线程参数传递,而不是通过静态参数传递。因为它本身就是线程安全的。参数是可用的:为什么不使用它?抱歉,但是变量传递约定与线程安全无关。不管怎么说,我只是为了演示的目的介绍了一个简化的例子;我通常不提倡使用全局变量…我得到下一个错误
无法使用类型为'JNIEnv**'(也称为'JNIEnv_**')的右值初始化类型为'void**'的参数jvm->AttachCurrentThread(&jnv,NULL)代码>