2009-09-16 28 views
12

Tôi đang viết một ứng dụng Java sử dụng thư viện C++ thông qua giao diện JNI. Thư viện C++ tạo ra các đối tượng kiểu Foo, được truyền hợp lệ qua JNI tới Java.Chia sẻ luồng đầu ra thông qua giao diện JNI

Giả sử thư viện có chức năng đầu ra

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

và tôi có một Java OutputStream out. Làm thế nào tôi có thể gọi Foo::print từ Java để đầu ra xuất hiện trên out? Có cách nào để ép buộc OutputStream thành một số std::ostream trong lớp JNI không? Tôi có thể nắm bắt đầu ra trong bộ đệm lớp JNI và sau đó sao chép nó vào out?

Trả lời

0

Làm cách nào tôi có thể gọi Foo :: in từ Java để đầu ra xuất hiện?

Về mặt khái niệm, cách để lấy Foo :: print (...) để ghi vào một thể hiện Java OutputStream hiện có là viết một C++ std :: ostream implementation thực sự thực hiện một cuộc gọi lại vào Java để thực hiện đầu ra .

Điều đó nghe có vẻ, nhưng tôi không muốn viết/duy trì mã. Khi chạy, bạn sẽ có các cuộc gọi đi từ Java -> C++ -> Java, và có rất nhiều cơ hội để thực hiện các lỗi sẽ ngẫu nhiên phá vỡ JVM của bạn.

Có cách nào để ép buộc OutputStream thành std :: ostream trong lớp JNI không?

AFAIK no.

Tôi có thể chụp đầu ra trong bộ đệm lớp JNI và sau đó sao chép nó vào không?

Bạn có ý nghĩa đại khái như thế này không?

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

Có thể bạn có thể làm một việc như thế ... vào một ngày tốt lành với gió sau.

Nhưng tôi nghĩ bạn nên thực sự nhằm loại bỏ mã C++ thay vì cố gắng làm những điều ngày càng phức tạp trên JNI. IMO, JNI chỉ nên được sử dụng như một phương sách cuối cùng, và không phải là một đoạn cắt ngắn để tránh việc ghi lại nội dung trong Java.

+0

Thực hiện lại thư viện trong Java không phải là một tùy chọn (nó là lớn, trưởng thành và hiệu suất chuyên sâu). –

+0

Có lẽ bạn không nên cố gắng gọi nó từ Java sau đó. Quan điểm của tôi là bạn có khả năng tạo ra nhiều đau đớn cho bản thân và những người phải duy trì mã của bạn. –

+2

Trong khi tôi đồng ý với mã JNI thì khó có thể nói rằng bạn nên tránh nó không công bằng. Có chắc chắn là một nơi cho JNI, đặc biệt với các dự án di sản lớn như op đề cập và trong trường hợp của tôi API bên thứ 3 mà bạn phải sử dụng để hoàn thành công việc. Đây là một câu hỏi rất hợp lệ, tôi cũng đang tìm kiếm câu trả lời. – Cliff

1

Tôi đã đăng một writeup on my blog chi tiết trải nghiệm gần đây của tôi với cùng một vấn đề này. Nói chung, bạn muốn tránh cố gắng kết nối luồng đầu vào hoặc đầu ra cho một ứng dụng khách bằng bất kỳ ngôn ngữ nào vì nó ngụ ý chủ đề. Bạn có thể phân phối dần dữ liệu bằng cách sử dụng các cuộc gọi lại.

6

Tôi sẽ thực hiện một dòng chảy C++ mà bộ đệm ghi (Lên đến một số kích thước thiết lập) trước khi xóa những ghi vào java OutputStream qua JNI. Về phía java, bạn có thể sử dụng một thể hiện OutputStream thông thường, hoặc bạn có thể thực hiện xếp hàng khối đệm (về cơ bản là byte []) để tránh bất kỳ sự tranh chấp khóa nào giữa các luồng. Luồng đầu ra thực chỉ được sử dụng bởi một tác vụ trên một luồng khác kéo khối từ hàng đợi và ghi chúng vào OutpuStream.Tôi không thể nói nếu điều này là cần thiết hay không ở mức độ chi tiết này - bạn cũng có thể tìm thấy cách viết trực tiếp vào luồng đầu ra từ JNI hoạt động.

Tôi không chia sẻ các áp phích khác liên quan đến JNI và không thấy bất kỳ vấn đề nào khi sử dụng JNI cho việc này. Chắc chắn, người duy trì của bạn sẽ phải biết công cụ của họ, nhưng đó là về nó, và sự phức tạp của lớp Java/C++ có thể được quản lý với tài liệu, ví dụ và các trường hợp thử nghiệm. Trong quá khứ, tôi đã thực hiện một cầu nối Java <> COM với giao diện khá trò chuyện - không có vấn đề gì về hiệu suất, luồng hoặc bảo trì.

Với lựa chọn hoàn toàn miễn phí, sẽ không có JNI, nhưng đối với tôi, nó đã lưu ngày bằng cách làm cho có thể tích hợp chặt chẽ các hệ thống không tương thích khác.

+0

Điểm thưởng để không bẻ khóa trên JNI. – rdb

Các vấn đề liên quan