Re: [Q] Making functional called in one thread run in the context
of another?
spam@spam.com wrote:
I've written a java/JNI wrapper for an existing MFC program. Each MFC
function that I want to be available to java has a corresponding JNI
function.
Yikes! This sounds like a Bad Idea, and the Last Choice Only.
On initialisation, the java code calls a JNI method which creates a
CWinThread and starts the MFC application within it - pretty standard
stuff. Since the MFC application is running in a separate thread, each
JNI function uses a PostMessage() call to tell the MFC thread to call
the appropriate function. The JNI function are synchronous, i.e. the JNI
function won't return until the MFC program has responded to the message
posted and responded appropriately. This is necessary as the MFC code is
not re-entrant.
This all works fine.
Sure it does :-)
As a result of a JNI call, the MFC application may make a callback into
the java code to notify it of certain events (using GetMethodID,
CallVoidMethod and friends). Again this all works fine.
The problem comes when a callback needs to make a JNI call itself.
Since the callback occurs in the thread of the MFC application, the
original synchronous JNI call (the one that triggered the callback in
the first place) has not returned, so trying to make another JNI call
will cause a deadlock :-(
Here's the problem in slightly dodgy ASCII UML:
Java JNI MFC App
| | |
| func() | |
|________\| |
| /| PostMessage() \|
| |-----------------|
| | /|
| | callback() |
|/________|_________________|
|\ | |
| |
| func2() |
|________\| Deadlock
| /|
| |
You really should have two message queues going on here. One for the MFC
app, and one for the Java app. Alternatively, you should have your JNI
detect if its in a call already, and directly call the function instead
of using PostMessage().
func2() is called in the context of the MFC App.
That's pretty much the crux of the problem, which made we wonder if the
callback function can schedule a function call for when the original JNI
call has finished; that way it will be executed after func() returns.
You'd be better off scheduling the callback function to execute in a
different Java thread or event queue.
Another approach might be to avoid running the MFC application in its
own thread, and instead periodically call a dummy JNI message pump from
the java code. I don't know how responsive that would be, though, not
to mention that making repeated JNI calls could be expensive.
Port the original MFC program to Java. You'll get a more portable,
cleaner, and probably much less buggy program.
Good luck,
Daniel.
--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>