Question Brief
I am using C++ and Java in one process via JNI. For the use case in question, both a C++ thread and a Java thread are accessing the same data, they are doing so on the C++ side, and I want to properly synchronize the access.
So far, almost all of my JNI thread synchronization has been on the Java side where the answer is obvious: use the provided Java concurrency package and the built-in concurrency language features. Unfortunately, the answer is not so obvious on the C++ side.
What I've Tried so far Brief
I tried using a pthreads mutex thinking that it might work even though I'm not using pthreads to create threads, but that occasionally gets stuck when trying to lock - I'll show an example of that farther below.
Question Details
In my current, specific usage, c++ is polling for changes provided by Java on a 1 second timer (not what I'd like, but I'm not sure how I would make it event-driven given the nature of the legacy c++ code). The Java thread provides data by calling a native function and c++ copies the data into a c++ structure.
This is the type of situation in code (happens on 2 threads, Thread1 and Thread2):
Code Example
Note quite an SSCCE, as it's missing definitions for TheData
and TheDataWrapper
, but it doesn't really matter what they contain. Assume they merely contain a couple of public int
s if that helps your thought process (though, in my case, it's actually multiple arrays of int and arrays of float).
C++:
class objectA
{
void poll();
void supplyData(JNIEnv* jni, jobject jthis, jobject data);
TheDataWrapper cpp_data;
bool isUpdated;
void doStuff(TheDataWrapper* data);
};
// poll() happens on a c++ thread we will call Thread1
void objectA :: poll()
{
// Here, both isUpdated and cpp_data need synchronization
if(isUpdated)
{
do_stuff(&cpp_data);
isUpdated = false;
}
}
// supplyData happens on the Thread2, called as a native function from a java thread
void objectA :: supplyData(JNIEnv* jni, jobject jthis, jobject data)
{
// some operation happens that copies the java data into a c++ equivalent
// in my specific case this happens to be copying ints/floats from java arrays to c++ arrays
// this needs to be synchronized
cpp_data.copyFrom(data);
isUpdated = true;
}
Java:
class ObjectB
{
// f() happens on a Java thread which we will call Thread2
public void f()
{
// for the general case it doesn't really matter what the data is
TheData data = TheData.prepareData();
supplyData(data);
}
public native void supplyData(TheData data);
}
What I've Tried so far Details
When I tried pthread's locking as below, sometimes execution gets stuck in pthread_mutex_lock
. There should not be a deadlock in this situation, but just to test further I ran a scenario where supplyData
was not getting called at all (no data was being supplied), so no deadlock should have been possible, yet the first call to poll
will occasionally hang anyway. Perhaps using a pthreads mutex is not a good idea in this situation? Or perhaps I did something stupid and keep overlooking it.
So far, I tried using pthreads as below:
Code Example
C++:
class objectA
{
pthread_mutex_t dataMutex;
... // everything else mentioned before
}
// called on c++ thread
void objectA :: poll()
{
pthread_mutex_lock(&dataMutex);
... // all the poll stuff from before
pthread_mutex_unlock(&dataMutex);
}
// called on java thread
void objectA :: supplyData(JNIEnv* jni, jobject jthis, jobject data)
{
pthread_mutex_lock(&dataMutex);
... // all the supplyData stuff from before
pthread_mutex_unlock(&dataMutex);
}
Another option I thought about but have not done
I also considered using JNI to call back into java to request a lock using java's concurrency control. That should work, as either thread should block on the java side as needed. However, since accessing java from c++ is overly verbose, I was hoping to avoid going through that headache. I probably could make a c++ class which encapsulates JNI calls into java to request a java lock; that would simplify c++ code, though I wonder about the overhead of crossing back and forth over JNI just for thread locks.
It seems this is not necessary, per the comment by @Radiodef. It appears JNI includes MonitorEnter
/MonitorExit
functions which already handle the locking on the c++ side. There are pitfalls when using these at the same time as conventional locks on the java side, so please read here before using. I will be trying this out, and I expect that MonitorEnter
/MonitorExit
will be the answer and I recommend @Radiodef make an answer out of the comment.
Closing
How could I properly synchronize this? Should pthread_mutex_(un)lock work? If not, what can I use to synchronize between the C++ thread and the Java thread?
No JNI-specific C++ code is provided here since the JNI bridge is working and I can pass data back and forth. The question is specifically about proper synchronization between c++/java threads that are otherwise correctly communicating.
As mentioned before, I would prefer to avoid the polling scheme, but that might end up being another question. The legacy c++ code displays its part of the user interface in X/motif, and if I recall correctly the c++ thread above happens to be the event thread for display. The java thread will end up being the java event dispatch thread once the java user interface for this class is plugged in, though for now the java thread is an automated test thread; either way, it's a separate java thread.
The C++ thread is attached to the JVM. In fact, that is the C++ thread that created the JVM, so it should be attached by default.
I have been successful with plugging in other Java user interface elements into this program, but this is the first time C++ has needed non-atomic data from Java which needed to be synchronized. Is there a generally accepted correct way to do this?
MonitorEnter
andMonitorExit
necessarily solve the problem here. – Widower