方兆国 发表于 2013-07-19 11:43

JavaNative 使用Boost多线程库的问题

Java类文件package com.fangzhaoguo.primefinder;

public class NativeConcurrentPrimeFinder {

        static {
                System.loadLibrary("libJavaNative_ConcurrentPrimeFinder");
        }

        public NativeConcurrentPrimeFinder() {
        }

        public native boolean isPrime(final long number);

        public native int countPrime(final long number);

        public native int countPrime(final long lower, final long upper);

             public native int countPrimeInRange(final long lower, final long upper);
}
javah后的C头文件,并且经过我的修改,加入了自定义的变量/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
#include <boost/thread.hpp>
#include <stdio.h>
#include <math.h>
/* Header for class com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder */
jint total = 0;

#ifndef _Included_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder
#define _Included_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:   com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder
* Method:    isPrime
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_isPrime(
                JNIEnv *, jobject, jlong);

/*
* Class:   com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder
* Method:    countPrime
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrime__J(
                JNIEnv *, jobject, jlong);

/*
* Class:   com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder
* Method:    countPrime
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrime__JJ(
                JNIEnv *, jobject, jlong, jlong);

/*
* Class:   com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder
* Method:    countPrimeInRange
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrimeInRange(
                JNIEnv *, jobject, jlong, jlong);

#ifdef __cplusplus
}
#endif
#endif
Mingw编译的C++文件 ,使用了Boost库,并且在链接时使用了system和thread两个动态链接库,编译正常/*
* com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder.c
*
*Created on: 2013年7月18日
*      Author: root
*/

#include "com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder.h"

JNIEXPORT jboolean JNICALL Java_com_fangzhaoguo_primefinder_NativePrimeFinder_isPrime(
                JNIEnv *env, jobject obj, jlong number) {
        jlong i = 0;
        if (1 >= number) {
                return 0;
        }
        for (i = 2; i <= sqrt(number); i++) {
                if (0 == number % i) {
                        return 0;
                }
        }
        return 1;
}

JNIEXPORT void JNICALL Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrimeInRange(
                JNIEnv *env, jobject obj, jlong lower, jlong upper) {
        jlong i = 0;
        for (i = lower; i < upper; i++) {
                if (Java_com_fangzhaoguo_primefinder_NativePrimeFinder_isPrime(env, obj,
                                i)) {
                        total++;
                }
        }
}

JNIEXPORT jint JNICALL Java_com_fangzhaoguo_primefinder_NativePrimeFinder_countPrime__J(
                JNIEnv *env, jobject obj, jlong number) {
        using namespace boost;
        jlong start = 0, end = 0;
        jlong range = number / 4;
        jint i = 0;
        for (i = 0; i < 4; i++) {
                start = 0 + range * i;
                if (i < 3) {
                        end = start + range;
                } else {
                        end = number;
                }
                thread mythread(
                                Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrimeInRange,
                                env, obj, start, end);
        }
        return total;
}

JNIEXPORT jint JNICALL Java_com_fangzhaoguo_primefinder_NativePrimeFinder_countPrime__JJ(
                JNIEnv *env, jobject obj, jlong lower, jlong upper) {
        jlong i = 0;
        for (i = lower; i < upper; i++) {
                if (Java_com_fangzhaoguo_primefinder_NativePrimeFinder_isPrime(env, obj,
                                i)) {
                        total++;
                }
        }
        return total;
}
但是现在的问题是在java中运行时报错,不管使用C写还是加载boost类的C++写,都报相同的错误。有不使用C/C++多线程的例子,可以正常使用
以下是报错内容Exception in thread "main" java.lang.UnsatisfiedLinkError: com.fangzhaoguo.primefinder.NativeConcurrentPrimeFinder.countPrime(J)I
        at com.fangzhaoguo.primefinder.NativeConcurrentPrimeFinder.countPrime(Native Method)
        at com.fangzhaoguo.primefinder.Main.timeAndCompute(Main.java:58)
        at com.fangzhaoguo.primefinder.Main.main(Main.java:6)

rover12421 发表于 2013-07-20 02:43

System.loadLibrary("libJavaNative_ConcurrentPrimeFinder");你Android里的模块名是"libJavaNative_ConcurrentPrimeFinder"?JNICALL Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrime__J
Java_com_fangzhaoguo_primefinder_NativePrimeFinder_countPrime__JJ为啥你J前面是两个"_",应该只有一个"_"才对.你javah生成后仔细对比下看看

方兆国 发表于 2013-07-20 18:04

rover12421 发表于 2013-07-20 02:43 static/image/common/back.gif
你Android里的模块名是"libJavaNative_ConcurrentPrimeFinder"?为啥你J前面是两个"_",应该只有一个"_"才对. ...

我用javah生成就这样,使两个下划线(刚刚又试了一下)。
我还有一个疑惑,我在JavaNative的C函数调用一个函数,是必须按照javah生成的格式写,还是按照普通的C函数写

rover12421 发表于 2013-07-20 20:16

回复 3# 方兆国


    有两种方式,一种是你现在的这种,必须使用javah生成的函数名.还有一种是在jni_onload里注册.这样的函数名就可以随意
比如:package com.kill;

public class Check {
    static {
      /**
         * 加载动态库
         */
      System.loadLibrary("kill");
    }
      
    private static native int kill();
}第一种:JNIEXPORT jint JNICALL Java_com_rover12421_iamemulated_IAmEmulatedActivity_test
(JNIEnv * env, jclass clazz)
{
      return 0;
}
第二种:

# define NELEM(x) ((int) (sizeof(x) / sizeof((x))))

JNIEXPORT jint JNICALL test(JNIEnv * env, jclass clazz);

static JNINativeMethod methods[] = {
                {"kill", "()I", (void*)test},
};

static const char *classPathName = "com/kill/Check";

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
        JNIEnv* env = NULL;
        jclass clazz;
        //获取JNI环境对象
        if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
                return JNI_ERR;
        }


        //注册本地方法Load 目标类
        clazz = (*env)->FindClass(env,classPathName);
        if (clazz == NULL) {
                return JNI_ERR;
        }


        //注册本地native方法
        if((*env)->RegisterNatives(env, clazz, methods, NELEM(methods)) < 0) {
                return JNI_ERR;
        }

        /* success -- return valid version number */
        return JNI_VERSION_1_4;
}

JNIEXPORT jint JNICALL test(JNIEnv * env, jclass clazz)
{
       return 0;
}其实第二种注册方式,运行效率会更高

rover12421 发表于 2013-07-20 20:26

看你代码应该是没错的,你检查下修改的代码是否编译进so了
打开so查找Java_com_fangzhaoguo_primefinder_NativeConcurrentPrimeFinder_countPrime__J这个字符串,如果有的话,应该是没问题的才是

方兆国 发表于 2013-07-20 23:00

rover12421 发表于 2013-07-20 20:26 static/image/common/back.gif
看你代码应该是没错的,你检查下修改的代码是否编译进so了
打开so查找Java_com_fangzhaoguo_primefinder_Na ...0000000068481550 T Java_com_fangzhaoguo_primefinder_NativePrimeFinder_countPrime
_J
00000000684816e0 T Java_com_fangzhaoguo_primefinder_NativePrimeFinder_countPrime
_JJ
0000000068481470 T Java_com_fangzhaoguo_primefinder_NativePrimeFinder_isPrime在动态链接库中是一个下划线


这是C版本的,用了C++ Boost的里面的函数名完全变了

rover12421 发表于 2013-07-21 00:32

回复 6# 方兆国


    应该是找到原因了,应该是"_"的问题,我测试下看看

rover12421 发表于 2013-07-21 01:51

测试发现,只要是有同名的方法,方法名和参数之间就是用两个"_"分割的,编译的链接库里也是两个"_"的

还有个问题没问你System.loadLibrary("libJavaNative_ConcurrentPrimeFinder");windows下加载的是libJavaNative_ConcurrentPrimeFinder.dll文件,linux下加载的是liblibJavaNative_ConcurrentPrimeFinder.so文件.不知道你是啥平台.对应的文件对不对
如果这个没问题,你就应该检查下,为啥源代码是两个"_",而你编译之后的动态链接库却只有一个"_"

方兆国 发表于 2013-07-21 11:39

rover12421 发表于 2013-07-21 01:51 static/image/common/back.gif
测试发现,只要是有同名的方法,方法名和参数之间就是用两个"_"分割的,编译的链接库里也是两个"_"的

还有个 ...

我是Windows下的mingw。之前有过成功的例子,不过当时没有用到c多线程,现在带多线程的都是这个问题

rover12421 发表于 2013-07-21 11:44

回复 9# 方兆国


    你先检查下那个"_"问题,为啥不一致,实在不行,不用重名方法试试.如果只是多线程引起的话,是不是编译还需要加多线程支持参数
页: [1] 2
查看完整版本: JavaNative 使用Boost多线程库的问题