Learn how to use threads in Native code.
The thread standard supported in Native is POSIX threads, which defines a set of apis for creating and manipulating threads.
We can use POSIX threads in Native code as if we were using a library. We first need to include the library’s header file:
#include <pthread.h>
Copy the code
This header defines a number of thread-specific functions, some of which are used here for the moment.
Create a thread
POSIX thread creation functions are as follows:
int pthread_create(
pthread_t* __pthread_ptr,
pthread_attr_t const* __attr,
void* (*__start_routine)(void*),
void* arg);
Copy the code
Its parameters correspond to the following:
-
__pthread_ptr is a pointer to a variable of type pthread_t, which represents a handle to the return thread.
-
__attr is a pointer to the pthread_attr_t structure, which can be used to specify attributes of a new thread, such as stack size, scheduling priority, etc. If there are no special requirements, use the default value and set the variable to NULL.
-
The third argument is the function pointer to the thread starter, which is the method to execute when the thread starts. This is similar to the Run method in Java Runnable, which has the following function signature format:
void* start_routine(void* args)
Copy the code
The initiator treats the thread argument as a void pointer and returns a void pointer.
- The fourth argument is the thread launcher argument, the function argument, which can be NULL if no arguments need to be passed.
The pthread_create function returns 0 if executed successfully, or any other error code if executed successfully.
Next, we can experiment with the pthread_create method to create a thread.
First, create a function to run when the thread starts:
void *printThreadHello(void *);
void *printThreadHello(void *) {
LOGD("hello thread");
// Remember to have a return value
return NULL;
}
Copy the code
Note that the thread-start function must have a return value, without which it will crash.
This function is executed as soon as pthread_create is called.
Next create the thread:
JNIEXPORT void JNICALL
Java_com_glumes_cppso_jnioperations_ThreadOps_createNativeThread(JNIEnv *, jobject) {
pthread_t handles; // Thread handle
int result = pthread_create(&handles, NULL, printThreadHello, NULL);
if(result ! =0) {
LOGD("create thread failed");
} else {
LOGD("create thread success"); }}Copy the code
Since there are no attributes for this thread and no arguments are required for thread-run functions, the above program can be executed and printThreadHello is run on a new thread.
Attach the thread to the Java virtual machine
In the thread startup function above, we simply print the log. If we want to perform Java-related operations, such as calling Java functions from JNI, we need to use the Java virtual machine environment, that is, using the JNIEnv pointer. After all, all calling functions start with it.
Pthread_create creates a thread in C++ that is not recognized by the virtual machine. In order to interact with the Java space, you need to attach the POSIX thread to the Java virtual machine and then get the JNIEnv pointer for the current thread. Because the JNIEnv pointer is only valid in the current thread.
The AttachCurrentThread method attaches the current thread to the Java virtual machine and obtains a JNIEnv pointer.
The AttachCurrentThread method is invoked by the JavaVM pointer, which represents the Java virtual machine interface pointer and can be obtained when JNI_OnLoad is loaded and stored as a global variable
static JavaVM *gVm = NULL;
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) ! = JNI_OK) {return JNI_ERR;
}
gVm = vm;
return JNI_VERSION_1_6;
}
Copy the code
DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread DetachCurrentThread
Specific use is as follows:
First, we define the callback method in C++ thread in Java, mainly printing the thread name:
private void printThreadName(a) {
LogUtil.Companion.d("print thread name current thread name is " + Thread.currentThread().getName());
Thread.sleep(5000);
}
Copy the code
Then define the method to run in Native thread:
void *run(void *);
void *run(void *args) {
JNIEnv *env = NULL;
// Add the current thread to the Java virtual machine
// Assume there are arguments passed
ThreadRunArgs *threadRunArgs = (ThreadRunArgs *) args;
if (gVm->AttachCurrentThread(&env, NULL) = =0) {
// The current thread id is not the main thread
env->CallVoidMethod(gObj, printThreadName);
// Separate the current thread from the Java virtual machine
gVm->DetachCurrentThread();
}
return (void *) threadRunArgs->result;
}
Copy the code
Finally, create a thread and run the method:
// Create the parameters to pass
ThreadRunArgs *threadRunArgs = new ThreadRunArgs();
threadRunArgs->id = i;
threadRunArgs->result = i * i;
// Run the thread
int result = pthread_create(&handles, NULL, run, (void *) threadRunArgs);
Copy the code
With this call, Java-related functions can be called in Native threads.
Wait for the thread to return the result
As mentioned earlier, a thread-run function must have a return value. It initially returns a NULL pointer, and a new thread is started in a method. When the new thread runs, the method immediately returns and exits.
Now, you can also wait for the thread to finish executing in this method, and then get the result of the thread’s completion.
The pthread_JOIN method lets you wait for a thread to terminate.
int pthread_join(pthread_t __pthread, void** __return_value_ptr);
Copy the code
Among them:
- __pThread represents the handle to create the thread
- __return_value_ptr represents the result returned by a thread running a function
Use as follows:
for (int i = 0; i < num; ++i) {
pthread_t pthread;
// Create thread,
int result = pthread_create(&handles[i], NULL, run, (void*) threadRunArgs); }}for (int i = 0; i < num; ++i) {
void *result = NULL; // Thread execution returns the result
// Wait for the thread to finish executing
if(pthread_join(handles[i], &result) ! =0) {
throwByName(env, runtimeException, "Unable to join thread");
} else {
LOGD("return value is %d",result); }}Copy the code
If pthread_JOIN returns 0, the execution succeeds. If pthread_join is not 0, the execution fails.
Specific code examples can be found in my Github project, welcome Star.
Github.com/glumes/Andr…
JNI Series articles:
- Reference management in Android JNI
- Exception handling when Android JNI calls
- Android JNI basic operation
Welcome to pay attention to wechat public number: [paper talk], get the latest article push ~~~