Вызов Java из Фортрана с использованием JNI, многопоточность

1

Я пытаюсь передать массив из Fortran на Java, сделать некоторые вычисления в Java и вернуть значение в мою программу Fortran. Я использую JNI для вызова Java из Fortran. Я написал образец программы, и мой код выглядит следующим образом:

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
    Ой, извините за это! Я починил это.
Теги:
multithreading
fortran
jni

2 ответа

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;
}

Я добавил интерфейс для функции init в моей программе Fortran (mod.f95) и вызвал init() перед вызовом obj (double *, int *). Он отлично работает, и я получаю следующий результат:

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». Как мне исправить ошибку?
  • 0
    Я также добавил оператор "(* jvm) -> DestroyJavaVM (jvm);" прежде чем я верну результат, и я все еще получаю те же ошибки.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню