Used in multiple JNI threads

Source: Internet
Author: User

Previous Article http://www.bkjia.com/kf/201202/119073.htmlsaid that JNIEnv is A thread-related variable, that is, thread A has A JNIEnv variable, and thread B also has A JNIEnv variable. Due to thread-related, therefore, thread A cannot use the JNIEnv struct variable of thread B.

 


Problem description:

A java object uses JNI to call a send () function in the DLL to send messages to the server. A message is returned immediately after the server message arrives, at the same time, the JNI interface pointer JNIEnv * env (Virtual Machine environment pointer) and jobject obj are saved in the DLL variables. after a period of time, the message receiving thread in the DLL receives the message sent from the server and tries to call the method of the previous java object (equivalent to the JAVA callback method) through the stored env and obj) in this case, the program will suddenly exit (crash ).

That is, the front-end JAVA thread sends a message, and the backend thread processes the message. It belongs to two different threads and cannot use the same JNIEnv variable. A mechanism can be used here: the global JavaVM * pointer is used to obtain the JNIEnv * pointer of the current thread, which is similar to the principle that two threads in C ++ use TLS for local storage.

 


Specific Method:

Obtain the global JavaVM variable:

/* Our VM */
JavaVM * g_vm;


Env-> GetJavaVM (& g_vm); // to get the JavaVM pointer. After obtaining the pointer, save the JavaVM.

 


The JNIEnv pointer of the thread. The JNIEnv method is obtained in the thread:

JNIEnv * e;
JavaVMAttachArgs thread_args;


Thread_args.name = "NFC Message Loop ";
Thread_args.version = nat-> env_version;
Thread_args.group = NULL;

G_vm-> AttachCurrentThread (& e, & thread_args); // The following parameters can be null.

While (1 ){

//...

}

G_vm-> DetachCurrentThread (); // after use

 


After this, JNIEnv can be used independently by each thread.

 


If we need to call back the JAVA method, jobject cannot be shared among multiple threads, so it can be used in multiple threads:

Gs_object = env-> NewGlobalRef (obj); // create a global variable.


Saves the imported obj (local variable) to gs_object, so that other threads can use this gs_object (global variable) to manipulate this java object.

The complete sample code is as follows:

Java code: Test. java:


[Java]
Import java. io .*;
Class Test implements Runnable
{
Public int value = 0;
Static {System. loadLibrary ("Test ");}

Public native void setEnev (); // local method

Public static void main (String args []) throws Exception
{
Test t = new Test ();
<Span style = "color: # FF0000;"> t. setEnev (); // call the local method </span>

While (true)
{
Thread. sleep (1000 );
System. out. println (t. value );
}
}
}
Import java. io .*;
Class Test implements Runnable
{
Public int value = 0;
Static {System. loadLibrary ("Test ");}
 
Public native void setEnev (); // local method
 
Public static void main (String args []) throws Exception
{
Test t = new Test ();
<Span style = "color: # FF0000;"> t. setEnev (); // call the local method </span>
 
While (true)
{
Thread. sleep (1000 );
System. out. println (t. value );
}
}
}

 


JNI code Test. cpp:
Static JavaVM * gs_jvm = NULL;
Static jobject gs_object = NULL;
Static int gs_ I = 10;
 
JNIEXPORT void JNICALL Java_Test_setEnev (JNIEnv * env, jobject obj)
{
Env-> GetJavaVM (& gs_jvm); // save it to the global variable JVM
// You cannot directly assign values to the global variables in obj to the DLL. You should call the following function:
Gs_object = env-> NewGlobalRef (obj );
 
HANDLE ht = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFun, 0, NULL, NULL );
}


Void WINAPI ThreadFun (PVOID argv) // calls back the thread in JNI.
{
JNIEnv * env;
Gs_jvm-> AttachCurrentThread (void **) & env, NULL );
Jclass cls = env-> GetObjectClass (gs_object); // obtain the global object in the JAVA thread
JfieldID fieldPtr = env-> GetFieldID (cls, "value", "I"); // obtain the JAVA object
 
While (1)
{
Sleep (100 );
// Change the property value of the JAVA object (callback JAVA)
Env-> SetIntField (gs_object, fieldPtr, (jint) gs_ I ++ );
}
}

 

As long as you understand the TLS usage, you can easily understand the above content.

Here is an additional introduction to TLS (thread-local storage), which is excerpted online:

A thread is a unit of execution. Multiple Threads in a process share the address space of the process. A thread generally has its own stack, however, if you want to implement a global variable to get different values between different threads, it will not be affected. One way is to adopt the thread synchronization mechanism, such as adding a critical section or mutex to the reading and writing of this variable. However, this is at the cost of sacrifice efficiency. Can it be left unlocked? This is what Thread Local Storage does.

 

In Windows, it is identified based on the Local Storage index of the thread (the allocation and release of this identifier are completed by TlsAlloc and TlsFree ), with this "identifier", you can call TlsGetValue or TlsSetValue in each thread to read or set the respective values of each thread;

DWORD TlsAlloc (void );


BOOL TlsFree (DWORD dwTlsIndex );
LPVOID TlsGetValue (DWORD dwTlsIndex );
BOOL TlsSetValue (DWORD dwTlsIndex, LPVOID lpTlsValue );

 


Interface functions for linux:

Int pthread_key_create (pthread_key_t * key, void (*) (void *));
Int pthread_key_delete (pthread_key_t );
Void * pthread_getspecific (pthread_key_t );
Int pthread_setspecific (pthread_key_t, const void *);

From andyhuabing's column

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.