您的位置:首页 > 移动开发 > Android开发

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

2010-03-28 19:50 337 查看
一、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);指令來讓各線程能達到同步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: