2015-10-09 1 views
4

У меня проблема с Java Native Access: у меня есть C-библиотека с одной функцией, скажем foo(). Эта функция имеет память - счетчик - с увеличением с каждым вызовом. Возможно ли создать два экземпляра этой библиотеки в рамках одного и того же Java-процесса, чтобы счетчики были независимыми?Как создать несколько экземпляров одной и той же библиотеки с помощью JNA?

спасибо.

Вот код:

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.foo(); // >1 
a.foo(); // >2 
b.foo(); // >1 
a.foo(); // >3 
b.foo(); // >2 
a.foo(); // >4 

Большое спасибо

Вот как я попытаться создать экземпляр из Lib:

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

ответ

2

Самый простой способ сделать это случиться, чтобы просто сделать копию общей библиотеки с другим именем.

Поведение по умолчанию для загрузки разделяемой библиотеки заключается в том, что независимо от того, сколько раз вы ее загружаете, вы фактически получаете один и тот же экземпляр.

В зависимости от базовой ОС вы можете предоставить опцию open, которая указывает, что вы хотите полностью независимую копию или копию с общим кодом, но независимыми данными. См. Документацию для LoadLibrary() (окна) и dlopen() (все остальное). Эти параметры можно передать в ОС через опцию Library.OPTION_OPEN_FLAGS, переданную в Native.loadLibrary().

JNA может поддерживать загрузку разделяемых библиотек с любым количеством дополнительных параметров, а на стороне Java она будет поддерживать одну и ту же библиотеку, загруженную различными опциями, в виде двух независимых библиотек. Тем не менее, он обычно обрабатывает две нагрузки с теми же параметрами, что и одна и та же логическая разделяемая библиотека (NativeLibrary представляет любой заданный загрузчик разделяемой библиотеки и кэшируется в соответствии с именем и параметрами библиотеки). Таким образом, вы можете подделать его и загрузить одну и ту же библиотеку дважды, предоставив опцию библиотеки, которая фактически игнорируется (например, макет-макет типа).

Обратите внимание, что даже если вы подделываете JNA, вы должны убедиться, что флаги, которые вы передаете базовой системе (через Library.OPTION_OPEN_FLAGS), гарантируют, что ОС сделает то, что вы хотите. В противном случае сама ОС просто вернет вам тот же экземпляр библиотеки, и JNA не сможет с этим поделать.

EDIT

Выяснить какие флаги вам нужно перейти к ОС, чтобы гарантировать, что она дает вам уникальную ручку каждый раз, когда вы называете dlopen/LoadLibrary (или, по крайней мере, ручку, которая обеспечивает независимые сегменты данных) , Флаг, который вы ищете в Linux, скорее всего RTLD_PRIVATE. Это флаг, который необходимо передать в Library.OPTION_OPEN_FLAGS. После этого перейдите в фиктивный вариант к карте опций 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_PRIVATE. Непонятно, что вы можете загружать одну и ту же библиотеку с независимым сегментом данных в OSX или Windows без отдельной копии разделяемой библиотеки. Под linux также существует dlmopen, но JNA не использует его.

Если вы связываете общую библиотеку с JNA, вы можете попросить JNA распаковать ее для вас (Native.extractFromResourcePath()), если необходимо, несколько раз (что дает вам несколько копий загружаемой общей библиотеки).

+0

Спасибо за ваш ответ. Проблема в том, что мне нужно динамическое количество экземпляров. Таким образом, опция копирования не является опцией. Другое решение для меня не совсем понятно. Ich установил опцию OPTION_OPEN_FLAGS в HasMap. Единственными возможными значениями являются -1, 0 и 1 (все остальные выбрасывают исключения). Во всяком случае, это не приводит к разным экземплярам библиотеки. Также я установил несколько фиктивных ключей с разными значениями. Также в этом случае я получаю только ту же проблему. – Jens

+0

Включите фактические исключения, возникающие при попытке использовать разные значения OPTION_OPEN_FLAGS, а также специальный метод, используемый для передачи флагов. Этот параметр должен принимать любое целочисленное значение (-1 рассматривается как «по умолчанию»). – technomage

+0

Кажется, это ошибка, данная ОС: Исключение в потоке «main» java.lang.UnsatisfiedLinkError: Falscher Parameter. Это означает «неправильный параметр». Я добавляю код к вопросу выше. – Jens

Смежные вопросы