Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / October 2007

Tip: Looking for answers? Try searching our database.

[Q] Making functional called in one thread run in the context of another?

Thread view: 
spam@spam.com - 11 Oct 2007 08:35 GMT
Hiya

I have an JFrame-derived MainFrame class which creates a worker thread.  The
thread needs to be able to call MainFrame functions, but ideally I'd like them
to be called in the context of the main application thread rather than that of
the worker thread.  I guess I'm looking for a way to schedule a function call
for when the main thread is next idle.

Is there a way to achieve this?

Regards,

--Jon
spam@spam.com - 11 Oct 2007 09:57 GMT
> Hiya
>
[quoted text clipped - 5 lines]
>
> Is there a way to achieve this?

Obviously I meant 'function' in the subject, not 'functional' :-)

Regards,

--Jon
Matt Humphrey - 11 Oct 2007 12:07 GMT
| > Hiya
| >
[quoted text clipped - 7 lines]
|
| Obviously I meant 'function' in the subject, not 'functional' :-)

Shifting execution to the EDT (main GUI thread) you can use
SwingUtilities.invokeLater or invokeAndWait.  It's typical for a worker
thread to pass back to the EDT upon completion to update the display, or
during operation to update status.  Otherwise, if you're not updating the
GUI, the only real reason to transfer to the EDT is to avoid synchronization
problems with your application data structure.  If you can describe what
you're trying to do in more detail there may be a better, more direct
solution for it.  Generally, however, it's not possible to have a call
executed in a different thread unless that thread was designed with that
purpose in mind.

Matt Humphrey http://www.iviz.com/
spam@spam.com - 11 Oct 2007 13:56 GMT
> | > Hiya
> | >
[quoted text clipped - 18 lines]
> executed in a different thread unless that thread was designed with that
> purpose in mind.

Thanks for the reply, I'll look into those functions.  I'll try and describe
the issue I'm working on (please bear with me, it's a little complicated :-)

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.

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.

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
  |        /|
  |         |

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.

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.

Regards,

--Jon
Daniel Pitts - 11 Oct 2007 15:20 GMT
> 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
[quoted text clipped - 6 lines]
>
> 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,
[quoted text clipped - 23 lines]
>   |        /|
>   |         |
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.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

spam@spam.com - 18 Oct 2007 20:27 GMT
>> 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.

I spent some time looking into methods to create java wrappers, and this way
seemed to be about the only method in use.  What other approaches are there?
I need the java wrapper to be able to create and modify C++ objects that are
handled by the C++/MFC code (of course the java code doesn't interact with MFC
objects directly).

Please take my word that rewriting the whole application in java is not an
option in this case :-)

>> 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,
[quoted text clipped - 25 lines]
> 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

What exactly do you mean by 'message queue'?  I'm picturing a thread that sits
and wait for tasks to be passed to it, with the calling thread waiting for the
result.  Is this what you had in mind?

> detect if its in a call already, and directly call the function instead
> of using PostMessage().

That's an interesting idea, but looking at my code it would be a lot of work
to implement.

>> func2() is called in the context of the MFC App.
>>
[quoted text clipped - 4 lines]
> You'd be better off scheduling the callback function to execute in a
> different Java thread or event queue.

I ended up using invokeLater() to make the callback be, um, called in the
context of the EDT.  It's not a perfect solution, but it covers all the cases
I need.

>> Another approach might be to avoid running the MFC application in its
>> own thread, and instead periodically call a dummy JNI message pump
[quoted text clipped - 3 lines]
> Port the original MFC program to Java. You'll get a more portable,
> cleaner, and probably much less buggy program.

See above :-)

> Good luck,

Thanks for your reply,

Regards,

--Jon
Matt Humphrey - 11 Oct 2007 17:44 GMT
<snip prelude>

| Thanks for the reply, I'll look into those functions.  I'll try and describe
| the issue I'm working on (please bear with me, it's a little complicated
[quoted text clipped - 21 lines]
| 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 :-(

Ok, I get all that.  I'm not familiar with JNI to MFC, so let me just
confirm what I think you're saying.  Are you saying that a 2nd JNI call made
from the MFC callback thread will block, but that a 2nd call made from a new
thread will not? I think you mean something slightly different, as I would
expect the 2nd call to block even when made from a separate thread.  I can't
quite follow your UML ascii art, but further below I think you say that the
callback does not need to wait for the 2nd JNI call to complete. If that's
so, I think what you mean is that the 2nd call on a different thread will
block but eventually be answered asynchronously after the callback and
original JNI request have completed.

If that's the case, I think all you need to do is to create a
single-threaded executor service in your Java wrapper.  You only need one of
these--don't create one each time you make a request and hang onto it for
you application.

ExecutorService executor = Executors.newSingleThreadExecutor ();

Then have your callback fire off the request

executor.submit (new Runnable () {
public void run () {
// Do your stuff here.
}
});

(To simply fire off the request in a separate thread, you can just do)
Thread t = new Thread (new Runnable () {
public void run () {
// Do your stuff here
}});
t.start ();

You don't need to wait for the executor to finish.  It will simply queue up
your request and as the MFC thread becomes available each will be processed
in turn.  You can check out the API to see how to manage shutdown, etc. (A
thread on its own is not guaranteed to execute in order--you may get a 2nd
request that executes before the first one.)

If the 2nd JNI call must be synchronous, I think you're SOL.  I don't think
it will matter which thread it comes from, it will just block and you'll get
deadlock.  I don't know how the MFC access system is designed to operate in
that regard.

| 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
[quoted text clipped - 4 lines]
| code.  I don't know how responsive that would be, though, not to mention that
| making repeated JNI calls could be expensive.

I have systems that use hundreds of interlocked, signalling threads and I
don't have a problem with performance on that aspect. The more you can make
all requests asynchronous, the easier it becomes.  For synchronous requests
you need only figure out how to respond to request completion and where to
put results. You can use the executor above to receive all requests and let
each one handle its final update itself.  You'll have to decide what's
appropriate for the data structures you're trying to manage.

Cheers,
Matt Humphrey http://www.iviz.com/
Lew - 11 Oct 2007 17:08 GMT
> solution for it.  Generally, however, it's not possible to have a call
> executed in a different thread unless that thread was designed with that
> purpose in mind.

To design that purpose in mind, one can use various classes from
java.util.concurrent, such as the various Executors and Queues.

Doug Lea and Brian Goetz are the authors to read.

Signature

Lew

Daniel Pitts - 12 Oct 2007 00:36 GMT
> Shifting execution to the EDT (main GUI thread) you can use
> SwingUtilities.invokeLater or invokeAndWait.
Actually, if you're going to use the EDT at all, its best to use
EventQueue.invoke*
SwingUtilities delegates to EventQueue.invoke*. SwingUtilities was
created because older versions of AWT didn't have an event queue, so
it delegated to a different implementation.  The AWT EventQueue is
standard now, so you should use it directly.
--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Lew - 12 Oct 2007 01:14 GMT
>> Shifting execution to the EDT (main GUI thread) you can use
>> SwingUtilities.invokeLater or invokeAndWait.
[quoted text clipped - 4 lines]
> it delegated to a different implementation.  The AWT EventQueue is
> standard now, so you should use it directly.

For the converse, moving non-GUI actions off the EDT, there is the incomparable
<http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html>

Signature

Lew

spam@spam.com - 18 Oct 2007 20:17 GMT
> | > Hiya
> | >
[quoted text clipped - 14 lines]
> GUI, the only real reason to transfer to the EDT is to avoid synchronization
> problems with your application data structure.  If you can describe what

invokeLater() does exactly what I needed, thanks!

Regards,

--Jon
Roedy Green - 12 Oct 2007 08:42 GMT
>I have an JFrame-derived MainFrame class which creates a worker thread.  The
>thread needs to be able to call MainFrame functions, but ideally I'd like them
>to be called in the context of the main application thread rather than that of
>the worker thread.  I guess I'm looking for a way to schedule a function call
>for when the main thread is next idle.

A simple way to do it is to schedule the work packets with
invokeLater.  Then will generate events that will be processed by the
Swing thread.

see http://mindprod.com/jgloss/swingthreads.html
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.