如何在JNI C代码中创建线程

 

 

一、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)層的多線程安全》

转自:http://blog.csdn.net/linweig/archive/2010/03/28/5425411.aspx

作者:linweig

 

标签:

JNI 线程,JNI C代码中创建线程,JNI pthread_create,JNI层创建线程

 

你可能感兴趣的:(thread,c,jni,null,callback,methods)