120 likes | 218 Vues
Threads and GUIs. Confession: I’ve never liked GUI programming very much – so I haven’t done a lot of it I don’t like the visual design aspects But I have analyzed/debugged a lot of GUI code Objects have proven a very productive way to look at GUI implementation
E N D
Threads and GUIs • Confession: I’ve never liked GUI programming very much – so I haven’t done a lot of it • I don’t like the visual design aspects • But I have analyzed/debugged a lot of GUI code • Objects have proven a very productive way to look at GUI implementation • Problem: GUIs are made up of lots (and lots) of objects – buttons, menus, canvases, text areas, often overlayed on each other or implemented in terms of each other
Vulnerability • If GUI is multi-threaded, different threads access objects in different orders • Bottom-up for arriving input • Top-down for program output • Very difficult to design so that locks are acquired in the same order in all cases • -- Deadlock! • Hence, general design principle that GUI objects should be thread-confined to a single, event thread • In Java, AWT and Swing
The Basic Idea(s) • Event loops – MSFC, original Mac, X Window • System puts arriving input events in a single, system-wide event queue (producer) • Application loop pulls an event from the queue, figures out what it means (often a big case statement) and processes it (consumer) • Listener registration – AWT, Swing, Wx, … • Application registers code to process certain kinds of events • Internal toolkit loop calls all matching listeners for each event (in the event thread) • Either way, GUI objects are only touched by the single, event thread, hence thread-confined
How does it work? • Model-view-controller approach to GUI applications • Model: a collection of objects representing the state of the application • View: a collection of GUI objects showing the application on the screen • Controller: a collection of operations implementing changes to the state objects and GUI objects based on user input or program computation • May be distributed between Model and View objects or separate
How does it work? (2) • Arriving input event (associated with a GUI object) causes dispatcher to find listener and call a controller method, calls update Model method, calls update-View method • All in one thread
Main problem: long-running listeners • With only one thread handling events, what happens if one listener takes a long time? • Network I/O • File system I/O (local probably ok, but user can always sneak in a network connection these days) • Dialog boxes (so called modal dialogs) • User has lost control of the system – can’t tell it to stop the long-running task; can’t get it to do anything else
Techniques for long-running listener tasks • Perform them using a multi-threaded executor • Objects accessed (model) must be thread-safe • Can’t directly update the GUI • To update the GUI • Put an event in the system event-queue and have a listener to handle it • The listener runs in the event task! • Nested (inner classes)/static scoping make this less ugly than it might be
Example: Listing 9.5 Button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { button.setEnabled(false); label.setText(“busy”); backgroundExec.execute(new Runnable() { public void run() { doBigComputation(); // long-running GuiExecutor.instance().execute(new Runnable() { public void run () { button.setEnabled(true); label.setText(“idle”); } }); }…