[Tutor] Re: event-based programming

Derrick 'dman' Hudson dman@dman.ddts.net
Sat, 13 Jul 2002 13:58:33 -0500


--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable


Forewarning:
    The below text is rather heavily sprinkled with Java and also has
    some general GUI and multi-threaded programming concepts.

| On 13-Jul-2002 Erik Price wrote:
| > On Saturday, July 13, 2002, at 02:11  AM, Derrick 'dman' Hudson wrote:
| >=20
| >> Note - this is not real code, but it gives the idea.
| >> It is sort of a blend of the Java/Swing and GTK+ styles of
| >> implementaiton since those are the toolkits I've written the most code
| >> for, though not recently.  (actually, those are the only toolkits I've
| >> written applications for.  The two xforms labs don't really count, and
| >> I've only glanced at wxWindows)
| >=20
| > I did not see a Swing library in my module directory.  Is this a=20
| > standard offering with Python 2.2?
|=20
| Swing is a GUI library for Java.

If you want to use it from python, you can use the 'jython'
interpreter implementation (with all the other side-effects that has).

| >> This leads to another problem, though.  What if the main thread (event
| >> loop) and the worker thread both try to update some component of the
| >> gui at the same time?  A race condition.  Then add modal dialogs to
| >> the picture (modal dialogs are evil anyways).  One of the bugs I fixed
| >> at my last job (involving java/swing) was a total lockup of the gui
| >> under certain error conditions.  The problem was just that -- a worker
| >> thread tried to display a modal dialog.  However, it happened that
| >> that caused a deadlock in the system (without the dialog ever
| >> finishing painting).  The solution was quite simple -- wrap the
| >> dialog's creation in a "Runnable" object and queue it for execution in
| >> the main thread.  Swing has some utility functions
| >> (eg javax.swing.SwingUtils.invokeLater()) that allow you to pass a
| >> java.lang.Runnable object which will be added to the end of the event
| >> queue.  Then the event loop will run() that object (call its .run()
| >> method) in the main thread.
| >=20
| > I'm sorry, but this is confusing to me.  Although I'm not sure exactly=
=20
| > what a modal dialog is, I follow what you are saying -- but I don't=20
| > understand how the modal dialog locked up the gui.

To understand how it locked the gui you need to know what "modal"
means for a dialog.  Continue reading.

| And to help out, a modal window is one marked "you can do nothing
| else in this application until finish with me".  Generally they are
| a bad idea.

The reasons modal dialogs are bad are twofold :

1)  The user get really really (really) annoyed when he must cancel
    the unfinished operation in one dialog just to move the other
    window, or to click some other button first (because he forgot
    before opening the dialog), or to copy some information from the
    main window rather than re-typing it.

    Except in exceptional circumstances, they belong as part of the
    "UI Hall of Shame".  (not surprisingly, modal dialogs are mostly
    found in windows, and windows is quite full of modal dialogs)

    An example of an exceptional circumstance can be found in gvim.
    Suppose you have a file loaded in a buffer.  You make some changes
    in the buffer, but don't save it to disk yet.  In a separate
    window (maybe even a separate app) the file on disk is changed.
    gvim pops up a modal dialog that says "the file has changed on
    disk".  It has an "Ok" button to leave the buffer alone, and a
    "Load" button to discard the current buffer and (re)load the file
    from disk.  In this case, there really isn't anything sensible you
    can do in vim until it knows what to do about that external
    conflict.  (the curses version of vim displays the message and a
    command prompt, which must be answered before any other operations
    can be performed)

2)  It is tricky to ensure that your application doesn't create a
    deadlock for itself by attempting to display 2 (or more) modal
    dialogs at the same time (particularly alerts from long-running
    worker threads).  If you do try to display more than one, which
    one belongs on top?  Which one (should) get priority?

| > By putting the dialog's cretaion into a "Runnable" app, I am
| > assuming that this means you coded it to be performed within a
| > separate thread

Actually, the worker thread told the main event thread that it wanted
the operation to be performed.  I put the creation back in the main
thread because Swing, like all other GUI toolkits I am familiar with,
is not thread-safe.

If the dialog that was created wasn't modal, then it is possible that
the application would have continued running despite the data
corruption from not properly synchronizing the operations.  However,
since it was modal it prevented any other events from being handled.

| > But what I am unsure of is what is wrong with having the dialog
| > just come up (the way you had it originally).  This is very
| > interesting to me, learning about this topic.

Since the dialog was displayed from a worker thread, it so happened
that it corrupted some global data in the swing library (because the
lib isn't thread-safe).  Since the dialog was modal, no other events
could be processed until the user clicked "ok" in the dialog.
However, they couldn't click "ok" because the dialog hadn't been fully
painted due to race conditions and data corruption.


| > (perhaps this is what you were talking about by "spawning a
| > 'worker' thread"?).

As I (and shaleh) mentioned, the event loop is blocked while your
event handler is running.  It processes events in serial.  So suppose
your application is a web browser.  The user clicks "go" to load a
page.  Now you need to go and load the page, but that may take a long
time.  If you don't spawn a "worker" thread to handle the network,
etc, work, then the whole gui will be "locked" until the page is
loaded.  That is a very bad thing.  The user will be unable to cancel
the operation or do anything else with your application while the page
is being loaded.  In addition, if they move some other window over the
top of yours and then re-expose your app, your app will not repaint
the screen because the event loop is blocked.

The solution is to do the real work of the application outside of the
main event loop; in another thread.  Hence the term "worker thread"
since the thread does the real work while the "main" thread just
dispatches the events.  The worker thread will then die after it has
done its work.

| >> An additional reason all this is necessary is because most (all?) gui
| >> toolkits are not written to be thread-safe.  That is, they don't
| >> provide any internal locking or synchronization; meaning that they
| >> assume they will only be accessed from a single thread.  This is done
| >> because locking and synchronization adds both time and memory
| >> overhead, and for some applications it isn't necessary.  In addition,
| >> if you follow the guidelines I outlined above (as the swing utility
| >> functions make it fairly easy to do), you can avoid the issues
| >> altogether and not having the speed/memory overhead is a good thing.
| >=20
| > You mean by putting the code into a new "Runnable" instance?  I have no=
t=20
| > yet learned about the "Runnable" object yet.
|=20
| dman is again babeling about Java.

Guilty as charged, as far as the names go.

| As i understand it, Runnable is essentially an object which queues
| itself and when the time is right a slice of the program's time is
| given to it.

Have I ever mentioned that I hate Java?  :-)  Java does not consider
methods to be objects, nor does it have the concept (as in C) of a
"function pointer".  The only thing you can work with in java are
class instances.  To work around this (bad, IMO) limitation, the
standard library has an interface java.lang.Runnable.  It looks like
this :

public interface Runnable { public void run() ; }

Essentially it is the same as a function in python, or a class
instance that defines __call__.  It is merely a way of grouping a
bunch of executable statements together and passing them around as an
object.

In python (eg using jython) you would write this :

    # in your event handler
    gui_component =3D ...  # whatever you need to do to get a reference to
                         # the right component of your gui interface
    def bunch_of_statements() :
        # some operation on the component that *must* be performed from
        # the main AWTEventQueue thread
        gui_component.repaint()
    SwingUtilities.invokeLater( bunch_of_statements )

Just as the last statement seems to read, the main event thread will
invoke your function later.

In java you would write that as this :

    // in your event handler
    gui_component =3D ...  // whatever you need to do to get a reference to
                         // the right component of your gui interface

    SwingUtilities.invokeLater( new Runnable()
        {
            public void run()
            {
                // some operation on the component that *must* be
                // performed from the main AWTEventQueue thread
                gui_component.repaint() ;
            } } ) ;

Yes it is ugly.  Yes it is long-winded.  It is Java.  (I have
mentioned before that I dislike java :-))

If you don't understand this yet, glance over the docs on "anonymous
inner classes".  I created a subclass of Runnable (without naming it)
that overrides/defines the run() method.  I then created an instance
of the class (I only need one.  In fact, a simple function would
suffice, but java isn't python).  I pass that object to the util
method to be queued.

Somewhere inside the bowels of swing, there is some code that
resembles this :
    operation =3D the_queue.next() ;
    operation.run() ;  // here is where the Runnable object is run

If it was implemented in python, the second line would simply be
    run()
and use the standard built-in "callable" interface.

| I have one last unrelated question.  You (and many other sages on this
| list) have experience with Java.  I must admit that, while I really like
| Python, I am trying to learn Java too.  Is there an equivalent
| "tutor"-style list or forum for Java programming?  I have not found it,
| despite everywhere I look people are saying that the Java programming
| language has a large user base and support community.

My experience with java first comes from school.  One of the classes I
took (Design Patterns) used it as the implementation language for
demonstrating that we understood the concepts.  The next thing that
happened to me was I got a co-op job at a java shop.  I knew Eiffel
and C++ at the time (though now I know how little I actually knew of
them) and had that little experience with java.  Through my work there
I became quite familiar with many of the ins and outs of java and with
multi-threaded programming (I hadn't done multithreaded before, though
I had made a GTK-based gui app in C++).  Since then, every class I've
had has been java-based.  The CS and SE departments at my school have
really been pushing java (and dropped eiffel as the introduction
language) in the last few years.

As a result, unlike with python (which I learned from the web), I
don't know of any good resources on the web for learning java.  You
can learn the library by browsing the javadoc docs, but that won't
teach you the language.

As I've mentioned before, while Java is a significant improvement over
C++, it is still far behind Python.

As for the large user base, it is there.  However much of it is tied
up in schools, businesses and other non-Open/Free groups.  (sometimes
great OSS software comes from schools, but the rest of it is just
teaching types of projects in which the students must do all the work
on their own)

If you go job hunting, you'll find a lot more places that mention
    .   java
    .   c++
    .   windows
    .   VB
or some combination than you will places advertising python or unix
related positions.

(maybe those tools require a much larger support staff.  LOL! :-))

HTH,
-D

--=20
The fear of the Lord leads to life:
Then one rests content, untouched by trouble.
        Proverbs 19:23
=20
http://dman.ddts.net/~dman/

--liOOAslEiF7prFVr
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iEYEARECAAYFAj0weFkACgkQO8l8XBKTpRQT+gCfR3fYB7ytHhd5OIkY/R87XNAs
3pEAmQF/iRpPIMHCrHfhwFhU79Uu860n
=5e6x
-----END PGP SIGNATURE-----

--liOOAslEiF7prFVr--