SeaBass
SeaBass

Reputation: 121

JNI: Invoking CallVoidMethod from thread crashes

For some reason, when I try to access a java object (which persists throughout the entire program, BTW) from a thread, the program crashes. Here's a boiled down example to demonstrate the problem:

#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;
}

Any ideas as to what's going wrong?

Upvotes: 1

Views: 2664

Answers (2)

jayatubi
jayatubi

Reputation: 2212

I'd like to suggest you to try to find a way to post the invocation to main thread.

Since the entire process from "AttachCurrentThread" to "DetachCurrentThread" is not locked, the main thread may re"AttachCurrentThread", in some case, before the "run" finished. Thus there would still be issues.

Upvotes: 0

SeaBass
SeaBass

Reputation: 121

Okay, the problem seemed to be a missing NewGlobalRef call. This version works:

#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;
}

Upvotes: 2

Related Questions