2015-04-02 90 views
1

我想从Fortran传递一个数组到Java,在Java中进行一些计算并将值返回给我的Fortran程序。我使用JNI从Fortran调用Java。 我写了一个示例程序,我的代码如下:使用JNI从多线程调用Java,多线程

main.f95:

PROGRAM MAIN 
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER, C_INT, C_DOUBLE 
USE array_example 
IMPLICIT NONE 
INTERFACE 
    FUNCTION obj(c, c_size) RESULT(f) BIND(C, NAME='obj') 
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_DOUBLE, C_PTR, C_INT 
    TYPE(C_PTR), INTENT(IN), VALUE :: c 
    INTEGER(C_INT), INTENT(IN):: c_size 
    REAL(C_DOUBLE):: f 
    END FUNCTION 
END INTERFACE 

INTEGER :: x, y 
x=5 

CALL example(obj,x) 

END PROGRAM MAIN 

mod.f95:

MODULE array_example 
CONTAINS 
SUBROUTINE example(obj, N) 
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER, C_INT, C_DOUBLE, C_LOC 
IMPLICIT NONE 
INTEGER, INTENT(IN) :: N 
REAL(C_DOUBLE) :: res 
INTEGER :: j 
INTEGER(C_INT) :: flag 

INTERFACE 
    FUNCTION obj(c, c_size) RESULT(f) BIND(C, NAME='obj') 
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_DOUBLE, C_PTR, C_INT 
    IMPLICIT NONE 
    TYPE(C_PTR), INTENT(IN), VALUE :: c 
    INTEGER(C_INT), INTENT(IN):: c_size 
    REAL(C_DOUBLE):: f 
    END 
END INTERFACE 

REAL(C_DOUBLE), TARGET :: c_array(1:N) 
TYPE(C_PTR) :: cptr 

cptr = c_loc(c_array(1)) 

c_array(1:N)=(/2.6179917, 1.570795, 1.570795, 1.570795, 1.570795/) 

res = obj(cptr, N) 

PRINT *, res 

END SUBROUTINE 
END MODULE 

objFuncC.c

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

extern double obj(double *, int *); 

JNIEnv* create_vm(JavaVM **jvm) 
{ 
    JNIEnv* env; 
    JavaVMInitArgs args; 
    JavaVMOption options; 
    args.version = JNI_VERSION_1_6; 
    args.nOptions = 1; 
    options.optionString = "-Djava.class.path=./"; 
    args.options = &options; 
    args.ignoreUnrecognized = 0; 
    int rv; 
    rv = JNI_CreateJavaVM(jvm, (void**)&env, &args); 
    if (rv < 0 || !env) 
     printf("Unable to Launch JVM %d\n",rv); 
    else 
     printf("Launched JVM successfully\n"); 
    return env; 
} 


double obj(double *ptr, int *c_size) 
{ 
    JavaVM *jvm; 
    JNIEnv *env; 
    jdouble *dptr; 
    jdoubleArray newArray; 
    jint size; 
    double result; 


    size = *c_size; 
    dptr = (double *)ptr; 

    env = create_vm(&jvm); 
    if(env == NULL) 
     return 1; 
    newArray = (*env)->NewDoubleArray(env, size); 

    (*env)->SetDoubleArrayRegion(env, newArray, 0, size, (const jdouble*)dptr); 

    jclass objFuncJ_class; 
    jmethodID main_method; 
    jmethodID evaluate_method; 

    objFuncJ_class = (*env)->FindClass(env, "objFuncJ"); 
    evaluate_method = (*env)->GetStaticMethodID(env, objFuncJ_class, "evaluate", "([D)D"); 
    result = (*env)->CallStaticDoubleMethod(env, objFuncJ_class, evaluate_method, newArray); 

    printf("Result = %f\n",result); 
    return result; 

} 

objFunc .java

import java.io.*; 
import java.lang.*; 

public class objFuncJ 
{ 
    public static double evaluate(double[] position) 
    { 
     int m = 10; 
     double sum = 0.0; 
     for (int i = 1; i <= position.length; i++) 
     { 
     double xi = position[(i - 1)]; 
     double pow = 1.0; 
     double xiPow = Math.sin(i * (xi * xi)/Math.PI); 
     for (int j = 1; j <= (2 * m); j++) 
     { 
      pow *= xiPow; 
     } 
     sum += Math.sin(xi) * pow; 
     } 
     return -sum; 
    } 
} 

我得到以下输出:

Launched JVM successfully 
Result = -1.011206 
Unable to Launch JVM -5 
Unable to Launch JVM -5 
Unable to Launch JVM -5 
1.0000000000000000 

在“结果”的值是正确的输出。但是,多次执行失败。如何更改我的代码以处理函数的多个评估并仅创建一次Java JVM?

+0

哎呀,我们对此深感抱歉!我修好了它。 – 2015-04-02 19:12:27

回答

0

好吧我想我要去哪里错了。我改变objFuncC.c如下:

extern double obj(double *, int *); 
extern int init(); 
static JavaVM *jvm; 

JNIEnv* create_vm(JavaVM **jvm) 
{ 
    JNIEnv* env; 
    JavaVMInitArgs args; 
    JavaVMOption options; 
    args.version = JNI_VERSION_1_6; 
    args.nOptions = 1; 
    options.optionString = "-Djava.class.path=./"; 
    args.options = &options; 
    args.ignoreUnrecognized = 0; 
    int rv; 
    rv = JNI_CreateJavaVM(jvm, (void**)&env, &args); 
    if (rv < 0 || !env) 
     printf("Unable to Launch JVM %d\n",rv); 
    else 
     printf("Launched JVM successfully\n"); 
    return env; 
} 

int init() 
{ 
    JNIEnv *env_init; 
    env_init = create_vm(&jvm); 
    if(env_init == NULL) 
     return 1; 
} 

double obj(double *ptr, int *c_size) 
{ 
    JNIEnv *env; 
    jdouble *dptr; 
    jdoubleArray newArray; 
    jint size; 
    double result; 

    size = *c_size; 
    dptr = (double *)ptr; 

    jint rs = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL); 
    newArray = (*env)->NewDoubleArray(env, size); 

    (*env)->SetDoubleArrayRegion(env, newArray, 0, size, (const jdouble*)dptr); 

    jclass objFuncJ_class; 
    jmethodID main_method; 
    jmethodID evaluate_method; 

    objFuncJ_class = (*env)->FindClass(env, "objFuncJ"); 
    evaluate_method = (*env)->GetStaticMethodID(env, objFuncJ_class, "evaluate", "([D)D"); 
    result = (*env)->CallStaticDoubleMethod(env, objFuncJ_class, evaluate_method, newArray); 

    printf("Result = %f\n",result); 
    return result; 
} 

我打电话OBJ(双*,诠释*)之前添加函数初始化的接口在我的Fortran程序(mod.f95)和所谓的init()。它工作正常,我得到下面的输出:

Launched JVM successfully 
Result = -1.011206 
Result = -1.011206 
Result = -1.011206 
Result = -1.011206 
    -1.0112061116510644 

感谢您的帮助:)

0
evaluate_method = (*env)->GetStaticMethodID(env, objFuncJ_class, "evaluate", "([D)D"); 

不同意

public static double evaluate(double[] position, int flg) 

道德:不要尝试自己写JNI方法签名。使用javap -s的输出。这绝不是错的。

+0

我修好了。我仍然收到“无法创建JVM”错误。我该如何解决错误? – 2015-04-02 15:48:53

+0

我还添加了语句“(* jvm) - > DestroyJavaVM(jvm);”在我返回结果之前,我仍然得到相同的错误。 – 2015-04-02 16:07:04