一、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层创建线程