簡體   English   中英

C++ 多線程 Java JNI 方法調用

[英]C++ Multithread Java JNI method Call

我在 Java 中有一個簡單的類:

public class MyClass 
{
    public static void dummyTest() 
    {
    }
}

在 C++ 中,我執行以下 JNI 調用:

void c_call_function() 
{
    JNIEnv *env ...// the JNIEnv initialization in JNI...
    jclass clazz ...// the class initialization in JNI...

    jmethodID mid_dummyTest = env->GetStaticMethodID(clazz, "dummyTest", "()V");
    env->CallStaticIntMethod(clazz, mid_dummyTest);
}

如果單個程序調用靜態方法 c_call_function() 就可以了。

但是,如果多線程程序調用 c_call_function(),當通過 env->CallStaticIntMethod(clazz, mid_dummyTest); 行時,它會給我以下消息:

0x000000006FC77154 處的訪問沖突讀取到 0x0000000000000000

如果程序是多線程的,它使用相同的 JNIEnv 變量。 但我也嘗試通過 AttachCurrentThread 方法加載相同的 JNIEnv,它給了我同樣的問題。

只要我不創建任何本地引用,甚至不刪除或修改任何內容,多線程調用下面的方法時有什么限制?

    env->CallStaticIntMethod(clazz, mid_dummyTest);

應該為每個線程單獨獲取env 當且僅當線程不是由 JVM 啟動時,您才應該使用AttachCurrentThread() 對於發出AttachCurrentThread() 的每個線程,您必須調用DetachCurrentThread()

clazz應該為每個線程單獨獲取,或者您可以保存對從FindClass()接收到的結果的全局引用。

mid_dummyTest可以保存在一個全局變量中:這個 id 獨立於線程、 envclazz

我能夠運行類似的代碼(如下所示),其中我有多個線程訪問同一個 JVM(macOS)。 我正在使用 pthread。

重要的幾件事

  • attaching thread to JVM (" JNI 接口指針(JNIEnv) 只在當前線程中有效。如果另一個線程需要訪問Java VM,它必須首先調用AttachCurrentThread() 將自己附加到VM 並獲取JNI 接口指針. ”)
  • 加入線程
  • 我想最好使用互斥鎖來防止附加多個線程

主文件

#include <stdio.h>
#include <jni.h>
#include <pthread.h>

#define NUM_THREADS 6

pthread_mutex_t mutexjvm;
pthread_t threads[NUM_THREADS];

struct JVM {
  JNIEnv *env;
  JavaVM *jvm;
};

void invoke_class(JNIEnv* env);

void *jvmThreads(void* myJvm) {

  struct JVM *myJvmPtr = (struct JVM*) myJvm;
  JavaVM *jvmPtr = myJvmPtr -> jvm;
  JNIEnv *env = myJvmPtr -> env;

  pthread_mutex_lock (&mutexjvm);
  printf("I will call JVM\n");
  (*jvmPtr)->AttachCurrentThread(jvmPtr, (void**) &(env), NULL);
  invoke_class( env );
  (*jvmPtr)->DetachCurrentThread(jvmPtr);
  pthread_mutex_unlock (&mutexjvm);
  pthread_exit(NULL);
}

JNIEnv* create_vm(struct JVM *jvm)
{
    JNIEnv* env;
    JavaVMInitArgs vm_args;
    JavaVMOption options;
    options.optionString = "-Djava.class.path=./";

    vm_args.options = &options;
    vm_args.ignoreUnrecognized = 0;
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;

    int status = JNI_CreateJavaVM(&jvm->jvm, (void**)&env, &vm_args);
    if (status < 0 || !env)
        printf("Error\n");
    return env;
}

void invoke_class(JNIEnv* env)
{
    jclass Main_class;
    jmethodID fun_id;
    Main_class = (*env)->FindClass(env, "Main");
    fun_id = (*env)->GetStaticMethodID(env, Main_class, "fun", "()I");
    (*env)->CallStaticIntMethod(env, Main_class, fun_id);
}

int main(int argc, char **argv)
{
    struct JVM myJvm;
    myJvm.env = create_vm(&myJvm);

    if(myJvm.env == NULL)
        return 1;

    pthread_mutex_init(&mutexjvm, NULL);
    for(int i=0; i<NUM_THREADS; i++){
        pthread_create(&threads[i], NULL, jvmThreads, (void*) &myJvm);
        pthread_join(threads[i], 0);
    }
    (*myJvm.jvm)->DestroyJavaVM(myJvm.jvm);
}

主程序

public class Main {
    public static void main(String[] args){
        System.out.println("Hello, world");
    }
    public static int fun() {
        System.out.println("From JVM");
        return 0;
    }
}

生成文件

all: Main.class main

Main.class: Main.java
    javac Main.java

main.o: main.c
    llvm-gcc -c main.c \
    -I${JAVA_HOME}/include \
    -I${JAVA_HOME}/include/darwin/ \

main: main.o
    ld -o main -L${JAVA_HOME}/jre/lib/server/ \
        -ljvm \
    -rpath ${JAVA_HOME}/jre/lib/server \
    -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk \
    -demangle -dynamic -arch x86_64 \
    -macosx_version_min 10.12.0 \
    -lSystem \
    -rpath ${JAVA_HOME}/jre/lib/server/ \
    main.o

clean:
    rm -f Main.class main main.o

運行代碼后,您會得到以下結果:

./main
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM