Java 如何使用JNA创建同一库的多个实例?

Java 如何使用JNA创建同一库的多个实例?,java,libraries,jna,Java,Libraries,Jna,我对Java本机访问有一个问题:我有一个带有一个函数的C库,比方说foo()。此函数有一个内存-计数器-随着每次调用而增加。是否可以在同一java进程中创建此库的两个实例,以便计数器相互独立 多谢各位 下面是一些代码: public class A { public static class Lib { NativeLibrary libInstance = NativeLibrary.getInstance("myLibrary"); Func

我对Java本机访问有一个问题:我有一个带有一个函数的C库,比方说foo()。此函数有一个内存-计数器-随着每次调用而增加。是否可以在同一java进程中创建此库的两个实例,以便计数器相互独立

多谢各位

下面是一些代码:

public class A
{

    public static class Lib
    {
        NativeLibrary libInstance = NativeLibrary.getInstance("myLibrary");
        Function fn = lib.getFunction("foo");
    }

    private Lib lib = new Lib();

    public foo()
    {
        lib.fn.invoke(new Object[] {});
    }
}
如果我打电话:

A a = new A();
A b = new A();

a.foo(); // >1
a.foo(); // >2
b.foo(); // >3
a.foo(); // >4
b.foo(); // >5
a.foo(); // >6
但我想让a和b独立于图书馆工作:

a.foo(); // >1
a.foo(); // >2
b.foo(); // >1
a.foo(); // >3
b.foo(); // >2
a.foo(); // >4
非常感谢

以下是我尝试创建库实例的方式:

public class DriverLib 
{
    private static int counter = 1;

    NativeLibrary lib;

    Function stepAction;
    Function initialize;
    Function terminate;

    Pointer input;
    Pointer output;

    public DriverLib()
    {
        // create options 
        HashMap<String, Integer> options = new HashMap<>();
        options.put(Library.OPTION_OPEN_FLAGS, new Integer(counter++));

        lib = NativeLibrary.getInstance("mylib_win64", options);

        stepAction = lib.getFunction("step");
        initialize = lib.getFunction("initialize");
        terminate  = lib.getFunction("terminate");

        input  = lib.getGlobalVariableAddress("model_U");
        output = lib.getGlobalVariableAddress("model_Y");
    }
}
公共类DriverLib
{
专用静态整数计数器=1;
国家图书馆;
功能步进作用;
函数初始化;
功能终止;
指针输入;
指针输出;
公共司机室
{
//创建选项
HashMap选项=新建HashMap();
options.put(Library.OPTION_OPEN_标志,新整数(counter++));
lib=NativeLibrary.getInstance(“mylib_win64”,选项);
stepAction=lib.getFunction(“步骤”);
initialize=lib.getFunction(“initialize”);
terminate=lib.getFunction(“terminate”);
input=lib.getGlobalVariableAddress(“model_”);
output=lib.getGlobalVariableAddress(“model_Y”);
}
}

实现这一点的最简单方法是使用不同的名称复制共享库

加载共享库的默认行为是,无论加载多少次,都会得到相同的实例

根据底层操作系统的不同,您可以在open上提供选项,指示您需要一个完全独立的副本,或者一个包含共享代码但独立数据的副本。请参阅
LoadLibrary()
(windows)和
dlopen()
(其他所有内容)的文档。您可以通过传递给
Native.loadLibrary()
的选项
Library.option\u OPEN\u FLAGS
将这些选项传递给操作系统

JNA可以支持使用任意数量的附加选项加载共享库,在Java端,它将使用不同选项加载相同的库,作为两个独立的库。但是,它通常会将具有相同选项的两个加载视为相同的逻辑共享库(NativeLibrary表示共享库的任何给定加载,并根据库名称和选项进行缓存)。因此,您可以通过提供一个实际上被忽略的库选项(例如,一个伪类型映射器)来伪造它并加载完全相同的库两次

请注意,即使您伪造了JNA,您也必须确保传递给底层系统的标志(通过
库。OPTION\u OPEN\u flags
)确保操作系统按照您的要求运行。否则,操作系统本身只会返回相同的库实例,JNA对此无能为力

编辑

找出需要传递给操作系统的标志,以确保每次调用
dlopen
/
LoadLibrary
(或至少提供独立数据段的句柄)时,操作系统都会为您提供一个唯一的句柄。您在Linux上寻找的标志可能是
RTLD\u PRIVATE
。这是要传入
库的标志。选项\u OPEN\u标志
。然后,将一个伪选项传递给
Native.loadLibrary()
的选项映射;JNA应该忽略它无法识别的任何内容,但一个唯一的选项将强制JNA单独缓存每个库加载

++idx;
int flags = ...; // Must be flags legal to pass to dlopen/LoadLibraryEx
Map options = new HashMap() {
    { 
        put(Library.OPTION_OPEN_FLAGS, flags); 
        put("ignored-option", idx);
    }
}
lib[idx] = Native.loadLibrary("my-library", options);
查看您的系统是否支持
RTLD\u PRIVATE
标志。不清楚您是否可以在OSX或windows上加载具有独立数据段的同一库,而不需要共享库的单独副本。在linux下,也有,但JNA没有利用它


如果您将共享库与JNA捆绑在一起,您可以要求JNA为您解包(
Native.extractFromResourcePath()
),如果需要,可以多次解包(这会让您加载共享库的多个副本)。

谢谢您的回复。问题是,我需要动态数量的实例。因此,复制选项不是选项。另一个解决方案对我来说并不十分清楚。我在HasMap中设置了“打开标志”选项。唯一可能的值是-1、0和1(所有其他值都抛出异常)。无论如何,这不会导致库的不同实例。我还设置了一些具有不同值的伪键。同样,在这种情况下,我只会遇到同样的问题。请包括在尝试使用不同的
选项\u OPEN\u标志
值时引发的实际异常,以及用于传递标志的特定方法。该参数应接受任何整数值(-1被视为“默认值”)。似乎是线程“main”java.lang.UnsatisfiedLinkError:Falscher参数中的OS:Exception给出的错误。这意味着“参数错误”。我将代码添加到上面的问题中。第二个调用抛出错误。所以开放标志是2。感谢您的帮助。我在Linux上任何地方都找不到定义的
RTLD\u PRIVATE
标志。它是否已被重命名或删除?