Android Native(JNI)層的多線程安全

一、Native 程式如何誕生子線程

   Java層的各進程(Process) 都有主線程(Main Thread),各線程皆可能誕生子線程。這些Java層的線程都有可能並行呼叫同一個Native函數,因而Native函數的線程安全考量是必要的。

    Java線程一旦進入Native函數裡執行,在其執行過程中,也可能會誕生子線程,也可能多個線程並行執行同一個非Native的一般C/C++函數。該如何面對他們之間的線程安全問題呢?先談談如何誕生Native子線程呢請看範例:

 

/*  com_misoo_thread_JTX05.cpp    */

#include "com_misoo_thread_JTX05.h"

#include <utils/Log.h>

#include <utils/IPCThreadState.h>

#include <utils/ProcessState.h>

#include "android_runtime/AndroidRuntime.h"

using namespace android;

 

JavaVM *gJavaVM;

jmethodID   mid;

jclass      mClass;     // Reference to JTX05 class

jobject     mObject;    // Weak ref to JTX05 Java object to call on

char sTid[20];

unsigned int e1;

int x;

int sum;

pthread_t thread;

void* trRun( void* );

 

typedef multimap<string, JNIGlobalRef<jobject> *>MapOfObjects;

 

JNIEXPORT jstring JNICALL

Java_com_misoo_thread_JTX05_execute(JNIEnv *env, jobject thiz,jobject syncObj){

   ………

   int rr = pthread_create( &thread, NULL,trRun, NULL);

   ………

}

void* trRun( void* )

{

   ………

}

 

  使用函數pthread_create()函數來誕生Native層的子線程。

 

二、多個Native線程的安全問題

    由於Native函數裡執行的線程也能誕生子線程,所以也應該注意其線程安全問題。例如:

 

// JTX07.java

package com.misoo.thread;

import java.lang.ref.WeakReference;

import com.misoo.pk01.ac01;

 

import android.os.Handler;

import android.os.Message;

import android.os.Process;

 

public class JTX07 {

  private long refer;

  private static Handler h;

  private static int count;

 

  static {

        System.loadLibrary("JTX07_jni");

   }

  public JTX07(){

            init(new WeakReference<JTX07>(this));

            count = 0;

            h = new Handler(){

             public void handleMessage(Message msg) {

                       count++;

                       if(count == 1) {

                             ac01.ref.setTitle("env: " +String.valueOf(msg.arg1));

                          }

                       else if(count == 2)

                            ac01.tv.setText("env: " +String.valueOf(msg.arg1));

                    }

            };

  }

 

  public long calculate(){

        execute(this);

        //this.ssetTitle(ss);

        //ac01.ref.setTitle("ss:" + ss);

   return 0;

  }

   

 @SuppressWarnings("unused")

  private static voidcallback(int a, int b){

                Message m = h.obtainMessage(1, a, 3,null);

                     h.sendMessage(m);

   }

  private native voidinit(Object weak_this);

  private native Stringexecute(Object oSync);

  //private native Stringexecute(int x);

 }

 

 

/* com_misoo_thread_JTX07.h   */

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_misoo_thread_JTX07 */

 

#ifndef _Included_com_misoo_thread_JTX07

#define _Included_com_misoo_thread_JTX07

#ifdef __cplusplus

 

extern "C" {

#endif

/*

 * Class:     com_misoo_thread_JTX07

 * Method:    nativeSetup

 * Signature:(Ljava/lang/Object;)V

 */

void JNICALL Java_com_misoo_thread_Init

  (JNIEnv *,jobject, jobject);

 

/*

 * Class:     com_misoo_thread_JTX07

 * Method:    execute

 * Signature:(J)J

 */

jstring JNICALL Java_com_misoo_thread_Exec

  (JNIEnv *,jobject, jobject);

 

 

#ifdef __cplusplus

}

#endif

#endif

 

/*  com_misoo_thread_JTX07.cpp    */

#include "com_misoo_thread_JTX07.h"

#include <utils/Log.h>

#include <utils/IPCThreadState.h>

#include <utils/ProcessState.h>

#include "android_runtime/AndroidRuntime.h"

 

using namespace android;

 

JavaVM *gJavaVM;

jmethodID   mid;

jclass     mClass;     // Reference to JTX07class

jobject    mObject;    // Weak ref to JTX07 Javaobject to call on

char sTid[20];

unsigned int e1;

int x;

int sum;

pthread_t thread;

void* trRun( void* );

void callBack(JNIEnv *);

jobject    mSyncObj;

 

//typedef multimap<string,JNIGlobalRef<jobject> *> MapOfObjects;

 

//--------------------------------------------------------------

void Thread_sleep(int t)

{

   timespec ts;

   ts.tv_sec = t;

   ts.tv_nsec =0;

  nanosleep(&ts, NULL);

   return;

}

 

void JNICALL

Java_com_misoo_thread_setUp(JNIEnv *env, jobject thiz,jobject weak_this)

{

  jclass clazz =env->GetObjectClass(thiz);

  mClass =(jclass)env->NewGlobalRef(clazz);

  mObject  = env->NewGlobalRef(weak_this);

  mid =env->GetStaticMethodID(mClass, "callback","(II)V");

  return;

 }

 

jstring JNICALL

Java_com_misoo_thread_Exec(JNIEnv *env, jobject thiz,jobject syncObj){

   mSyncObj =env->NewGlobalRef(syncObj);

  

   int rr =pthread_create( &thread, NULL, trRun, NULL);

 

  Thread_sleep(4);

   callBack(env);

   //-----------------------------------------------------------

   long pid =getpid();

   sprintf(sTid,"%lu", pid);

   jstring ret =env->NewStringUTF(sTid);

   return ret;

}

//--------------------------------------------------------------------

void callBack(JNIEnv *env){

  env->MonitorEnter(mSyncObj);

  sum = 0;

  for(int i = 0;i<=10; i++)

          {

           sum +=i;

          Thread_sleep(1);

          }

   //-----------------------------------------------------------

  env->CallStaticVoidMethod(mClass, mid, sum, 666);

   //-----------------------------------------------------------

  env->MonitorExit(mSyncObj);

}

//--------------------------------------------------------------------

 

static const char *classPathName ="com/misoo/thread/JTX07";

 

static JNINativeMethod methods[] = {

   {"init",      "(Ljava/lang/Object;)V",

                   (void*)Java_com_misoo_thread_setUp},

   {"execute",   "(Ljava/lang/Object;)Ljava/lang/String;",

                  (void *)Java_com_misoo_thread_Exec}

};

 

/*

 * Registerseveral native methods for one class.

 */

static int registerNativeMethods(JNIEnv* env, constchar* className,

   JNINativeMethod* gMethods, int numMethods)

{

    jclass clazz;

 

    clazz =env->FindClass(className);

    if (clazz ==NULL) {

       LOGE("Native registration unable to find class '%s'",className);

        return JNI_FALSE;

    }

    if(env->RegisterNatives(clazz, gMethods, numMethods) < 0) {

       LOGE("RegisterNatives failed for '%s'", className);

        returnJNI_FALSE;

    }

 

    returnJNI_TRUE;

}

 

static int registerNatives(JNIEnv* env)

{

  if(!registerNativeMethods(env, classPathName,

                methods, sizeof(methods) / sizeof(methods[0]))) {

    returnJNI_FALSE;

  }

 

  returnJNI_TRUE;

}

 

 

//----------------------------------------------------------------------------

 

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

  

JNIEnv *env;

gJavaVM = vm;

int result;

 

LOGI("JNI_OnLoad called");

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4)!= JNI_OK) {

   LOGE("Failed to get the environment using GetEnv()");

    return -1;

}

 

if (registerNatives(env) != JNI_TRUE) {

       LOGE("ERROR: registerNatives failed");

        gotobail;

    }

  

    result =JNI_VERSION_1_4;

  

bail:

    returnresult;

}

 

//--------------------------------------------------------------------------------

void* trRun( void* )

{

    int status;

    JNIEnv *env;

    boolisAttached = false;

   

   Thread_sleep(1);

    status =gJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4);

    if(status< 0) {

       LOGE("callback_handler: failed to get JNI environment, "

            "assuming native thread");

        status =gJavaVM->AttachCurrentThread(&env, NULL);

        if(status< 0) {

           LOGE("callback_handler: failed to attach "

                "current thread");

           return NULL;

        }

        isAttached = true;

    }

   //-----------------------------------------------------------

    callBack(env);

   //-----------------------------------------------------------

 

   if(isAttached)

       gJavaVM->DetachCurrentThread();

    return NULL;

}

 

  主線程誕生了子線程去執行trRun()函數。必須先調用:

 

         gJavaVM->AttachCurrentThread(&env, NULL);

 

才能取得子線程自己所屬的JNIEnv物件之參考了,並且呼叫Callback()函數。之後,主線程也呼叫同一Callback函數。於是,在Callback()函數裡,使用env->MonitorEnter()env->MonitorExit(mSyncObj);指令來讓各線程能達到同步。

你可能感兴趣的:(Android Native(JNI)層的多線程安全)