JNI:C++コールバックJAVAの関数
サマリ
JNI、オブジェクトグローバル参照NewGlobalRef()、スレッドバインドJAVA仮想マシンAttachCurrentThread()
テストコード
JAVA
MainApp
Animal
Animal.javaはコールバック関数void logMessage(String)を提供する.
コンパイル「javac Animal.java」実行後、「javah-jni Animal」を実行してC++ヘッダファイルAnimal.hを生成します.
しんごうしょり
JNIコード
ヘッダファイルAnimal.h
ソースファイルAnimal.cpp
コンパイル
うんてん
参照 Javaプログラムのコンパイルと実行のプロセス JNI c++オブジェクトとjavaオブジェクトの相互関連
JNI、オブジェクトグローバル参照NewGlobalRef()、スレッドバインドJAVA仮想マシンAttachCurrentThread()
テストコード
JAVA
MainApp
//MainApp.java
import sun.misc.*;
public class MainApp {
static {
System.loadLibrary("animal");
}
public static void main(String[] args) {
TestSignal handler = new TestSignal();
Signal.handle(new Signal("TERM"), handler);
Signal.handle(new Signal("INT"), handler);
//Signal.handle(new Signal("USR1"), handler);
//Signal.handle(new Signal("USR2"), handler);
Animal animal = new Animal("Puppy");
animal.printName();
animal.setCallback();
while(handler.is_running()) {
System.out.println("I am Main Thread.");
try {
Thread.sleep(5000);
}
catch(InterruptedException e) {
System.out.println("InterruptedException.");
e.printStackTrace();
}
}
animal.closeCallback();
}
}
Animal
Animal.javaはコールバック関数void logMessage(String)を提供する.
//Animal.java
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void printName() {
System.out.println("Animal [" + name + "]");
}
private void logMessage(String msg) {
System.out.println("msg:" + msg);
}
public native void setCallback();
public native void closeCallback();
protected long mObj;
}
コンパイル「javac Animal.java」実行後、「javah-jni Animal」を実行してC++ヘッダファイルAnimal.hを生成します.
しんごうしょり
//TestSignal.java
import sun.misc.*;
@SuppressWarnings("restriction")
public class TestSignal implements SignalHandler {
public void handle(Signal arg0) {
System.out.println(arg0.getName() + " is recevied.");
if(arg0.getName() == "TERM") {
brunning = false;
}
}
public boolean is_running() {
return brunning;
}
private boolean brunning = true;
}
JNIコード
ヘッダファイルAnimal.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class Animal */
#ifndef _Included_Animal
#define _Included_Animal
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Animal
* Method: setCallback
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Animal_setCallback
(JNIEnv *, jobject);
/*
* Class: Animal
* Method: closeCallback
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Animal_closeCallback
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
ソースファイルAnimal.cpp
#include "Animal.h"
#include
#include
#include
#include
#include
static JavaVM *g_VM = NULL;
class CLog {
public:
CLog();
~CLog();
/*static CLog& instance() {
return CLog::static_clog_;
}*/
bool attach(JavaVM* vm, JNIEnv *env, jobject thiz);
bool detach(JNIEnv *env);
void set_JavaVM(JavaVM* jVM) {
javaVM_ = jVM;
};
private:
CLog(const CLog& obj);
CLog& operator=(const CLog& obj);
void attach_thread();
void dettach_thread();
static void *TestThread(void *arg);
private:
bool brunning_ = true;
JavaVM* javaVM_ = NULL;
JNIEnv *env_ = NULL;
jobject thiz_ = NULL;
pthread_t tid_;
//static CLog static_clog_;
};
//CLog CLog::static_clog_;
#define CONSTRUCT(T) { T *t = new T(); \
jclass clazz = (jclass)(*env).GetObjectClass(thiz); \
jfieldID fid = (jfieldID)(*env).GetFieldID(clazz, "mObj", "J"); \
jlong jstr = (jlong) (*env).GetLongField(thiz, fid); \
(*env).SetLongField(thiz, fid, (jlong)t);}
#define OBJECT(T,name) jclass clazz = (jclass)env->GetObjectClass(thiz); \
jfieldID fid = env->GetFieldID(clazz, "mObj","J"); \
T *name = (T *)env->GetLongField(thiz, fid);
#define DESTRUCT(T) {jclass clazz = (jclass)env->GetObjectClass(thiz); \
jfieldID fid = env->GetFieldID(clazz, "mObj","J"); \
T *object = (T *)env->GetLongField(thiz, fid); \
if(object != NULL) delete object; \
(*env).SetLongField(thiz, fid, (jlong)0);}
CLog::CLog() {
}
CLog::~CLog() {
}
bool CLog::attach(JavaVM* vm, JNIEnv *env, jobject object) {
javaVM_ = vm;
thiz_ = env->NewGlobalRef(object);
int ret = pthread_create(&tid_, NULL, CLog::TestThread, this);
printf("create thread, ret = %d.
", ret);
return true;
}
bool CLog::detach(JNIEnv *env) {
env->DeleteGlobalRef(thiz_);
thiz_ = NULL;
brunning_ = false;
pthread_join(tid_, NULL);
return false;
}
void CLog::attach_thread()
{
if(javaVM_ == NULL) return;
if(thiz_ == NULL) return ;
int ret = javaVM_->AttachCurrentThread((void **)&env_, NULL);
if(ret != 0)
{
}
}
void CLog::dettach_thread()
{
if(javaVM_ == NULL)
return;
javaVM_->DetachCurrentThread();
env_ = NULL;
}
void *CLog::TestThread(void *arg) {
CLog *pThis = (CLog *)arg;
pThis->attach_thread();
for(int i = 0; i < 100 && pThis->brunning_; ++i) {
char buffer[64];
sprintf(buffer, "%5d", i);
jstring msg_ = pThis->env_->NewStringUTF(buffer);
jclass clazz = pThis->env_->GetObjectClass(pThis->thiz_);
jmethodID jid = pThis->env_->GetMethodID(clazz, "logMessage", "(Ljava/lang/String;)V");
pThis->env_->CallVoidMethod(pThis->thiz_, jid, msg_);
pThis->env_->DeleteLocalRef(msg_);
sleep(5);
}
pThis->dettach_thread();
return NULL;
}
/*
* Class: Animal
* Method: setCallback
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Animal_setCallback
(JNIEnv *env, jobject thiz)
{
CONSTRUCT(CLog);
OBJECT(CLog,log);
if(log == NULL) {
return;
}
log->attach(g_VM, env, thiz);
}
/*
* Class: Animal
* Method: closeCallback
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Animal_closeCallback
(JNIEnv *env, jobject thiz)
{
{
OBJECT(CLog, log);
if (log == NULL) {
return;
}
log->detach(env);
}
DESTRUCT(CLog);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
//jint result = -1;
if(JNI_OK != vm->GetEnv((void**) &env, JNI_VERSION_1_4)) {
return -1;
}
assert(env != NULL);
g_VM = vm;
return JNI_VERSION_1_4;
}
コンパイル
g++ -std=c++11 -shared -I/home/syq/java/jdk-14.0.2/include -I/home/syq/java/jdk-14.0.2/include/linux -fPIC Animal.cpp -o libanimal.so
うんてん
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
java MainApp
参照