The SWT Thread
One of the key things no one seemed to tell us about SWT was that it ran in one thread by default. This has the unfortunate side-effect of freezing the GUI completely when you call a lengthy method from an event handler. This may seem like a big duh! to some people but I don’t recall Microsoft Visual Studio GUI event handlers requiring explicit threading. It seems like a definite control versus ease-of-use tradeoff.
This is exactly where a university education falls short: practical information. We covered the basics of threads in second year but even then we only brushed on it briefly, and never with a GUI. When you step in and try to use SWT in a production environment you’re completely clueless. No wonder the application was thrashing so badly, geez. Now because I’m using another thread the GUI is as smooth as silk.
The mutator event listeners that I implemented all cascade on the same thread: from the mutator to the controller to the model to the view when a change is made by a mutator. You want to call the mutator methods in a new thread from a GUI event handler so that the GUI won’t freeze. When the listeners are notified that the mutator made a change when it gets back to the view it throws SWTException because you tried to access/modify the GUI objects from a thread that is not the SWT thread — the same one doing the mutating also notifies and handles the listening.
So the last listener method (which still runs on the mutator thread) in the view has to notify the SWT thread that it wants to make a change. It does this by passing a Runnable object to SWT’s display object
public void itemRemoved(final ModelEvent me)
{
final TableViewer tableViewer = this.viewer;
if (tableViewer != null)
{
display.asyncExec(new Runnable()
{
public void run()
{
tableViewer.remove(me.getItem());
}
}
}
}
Notice the way that Runnable interface’s run() method is implemented inline. The objects that I used in the inline (tableViewer and me) must be final (constants) or the compiler will complain.
There were two separate ways I got around that. First, the me object was passed as a parameter to the listener method that contains this inline object. So I just made the parameter final in the method header. Second, the viewer changes in the object that contains this inline object, so before I make the inline object I just make a new final copy of it to tableViewer and use it instead of the non-final version.
Note that having the asyncExec() call in the view (actually it’s the TableViewer’s content provider) puts all of the SWT code togther in the user interface, rather than having some below it the GUI talking to the SWT thread which would increase coupling by putting SWT objects in the application code.
If you want to see how I implemented threading in AudioMan, it’s in the CVS repository under the project AudioManPoint2. There are all kinds of race conditions now because methods that should be synchronized, especially in the repository, aren’t yet. I’ll be working on that this week — I just wanted to see if the asyncExec() call worked, and it does.