Multithreading JNI:从线程崩溃调用CallVoidMethod

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

出于某种原因,当我试图从线程访问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_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)