Совместное использование потоков вывода через интерфейс JNI - PullRequest
13 голосов
/ 17 сентября 2009

Я пишу Java-приложение, которое использует библиотеку C ++ через интерфейс JNI. Библиотека C ++ создает объекты типа Foo, которые должным образом передаются через JNI в Java.

Предположим, библиотека имеет функцию вывода

void Foo::print(std::ostream &os)

и у меня есть Java OutputStream out. Как я могу вызвать Foo::print из Java, чтобы вывод появился на out? Есть ли способ привести OutputStream к std::ostream в слое JNI? Могу ли я захватить вывод в буфер слоя JNI, а затем скопировать его в out?

Ответы [ 3 ]

6 голосов
/ 27 апреля 2010

Я бы реализовал ostream C ++, который буферизует записи (до некоторого установленного размера), прежде чем сбрасывать эти записи в java OutputStream через JNI.

На стороне java вы можете использовать обычный экземпляр OutputStream или реализовать постановку в очередь буферных блоков (по существу, byte []), чтобы избежать возможного конфликта блокировок между потоками. Реальный выходной поток используется только задачей другого потока, которая извлекает блоки из очереди и записывает их в OutpuStream. Я не могу сказать, если это необходимо или нет на этом уровне детализации - вы вполне можете найти запись непосредственно в выходной поток из работ JNI.

Я не разделяю другие проблемы с постерами с JNI и не вижу проблем с использованием JNI для этого. Несомненно, ваши сопровождающие должны будут знать свое дело, но это все, и сложность уровня Java / C ++ может управляться с помощью документации, примеров и тестовых случаев. В прошлом я реализовывал Java <> COM-мост с довольно болтливым интерфейсом - никаких проблем с производительностью, многопоточностью или поддержкой.

Если бы у нас был абсолютно свободный выбор, не было бы JNI, но для меня это спасло день, сделав возможным тесную интеграцию несовместимых в других отношениях систем.

1 голос
/ 23 апреля 2010

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

0 голосов
/ 17 сентября 2009

Как я могу вызвать Foo :: print из Java так что выход появляется на выходе?

Концептуально говоря, способ заставить Foo :: print (...) записывать в существующий экземпляр Java OutputStream - это написать реализацию C ++ std :: ostream, которая фактически выполняет обратный вызов в Java для вывода.

Это звучит возможно, но я бы не хотел писать / поддерживать код. Во время выполнения вам будут приходить вызовы из Java -> C ++ -> Java, и существует множество возможностей для ошибок, которые могут случайно привести к сбою вашей JVM.

Есть ли способ заставить OutputStream в std :: ostream в Слой JNI?

AFAIK №

Могу ли я захватить вывод в буфер слой JNI, а затем скопировать его в из

Вы имеете в виду что-то вроде этого?

    MyJNIThing m = ...
    int myOstream = m.createMemoryBackedOStream(...); // native method
    ...
    m.someMethodWrapper(... myOStream); // native method
    ...
    byte[] data = m.getCapturedData(myOStream); // native method
    out.write(data);

Вы, вероятно, можете сделать что-то подобное ... в хороший день при следующем ветре.

Но я думаю, что вы действительно должны стремиться исключить код C ++, а не пытаться делать все более сложные вещи в JNI. IMO, JNI следует использовать только в качестве крайней меры, а не в качестве кратчайшего пути, чтобы избежать перекодирования в Java.

...