Android java + native data visibility
Let’s say I have two threads (except for the main thread) in my game application:
- GLRenderer thread (provided by
GLSurfaceView.Renderer
for Android). - Another thread (game thread).
Both threads use JNI to call some of the application’s C++ (that is, Android NDK) components.
Let’s say I allocate a direct IntBuffer
in Java (e.g. from a GLRenderer thread, but don’t assume so). Fact:
- This direct buffer is read by native code from the GLRenderer thread (that is, by the C++ component called via JNI).
- This direct buffer is sometimes written from other threads (game threads).
What is the (best) way to synchronize (effectively ensure data visibility) in the following two cases, i.e. to ensure that the native code in GLRenderer code sees the latest IntBuffer
content?
- Scenario #1: The game thread’s Java code writes to IntBuffer (e.g. via
IntBuffer.put()
). - Scenario #2: Native code called from the game thread writes
to IntBuffer
I think the standard Java sync works for both cases :
public void onDrawFrame(GL10 gl) { // the GLRenderer thread
// ...
synchronized (obj) {
callNativeCode1(); a JNI call; this is where the C++ native code reads the IntBuffer
}
}
public void run() { // the game thread
// ...
synchronized (obj) {
intBuffer.put(...); writing the buffer from managed code
}
// ...
synchronized (obj) {
callNativeCode2(); a JNI call; writing the buffer from C++ native code
}
}
Solution
Not knowing the details of sharing memory with JNI, but I recommend using AtomicIntegerArray
.
Your choice is:
synchronized
– you need to somehow implement the same functionality in JNI – not easy.volatile
– making the entire arrayvolatile
will be a problem.atomic
s – I would say the best route.
See also Package java.util.concurrent.atomic for:
The AtomicIntegerArray, AtomicLongArray, and AtomicReferenceArray classes further extend atomic operation support to arrays of these types. These classes are also notable in providing volatile access semantics for their array elements, which is not supported for ordinary arrays.
This basically ensures that as long as the JNI code doesn’t do anything to bypass Java’s cache flush semantics, then the JNI package should see a consistent and updated data view.
I
would recommend some important research to confirm this, but I believe this is the only way for you to achieve your goals.