5.9 Putting It All Together: Multithreading, Timers, Events, and the Event Loop
The event loop plays a critical role in synchronizing all of the user's actions, other operating system events, timers, and background threads with the user interface thread. This relationship can be summarized by the following description.
Events are generated by the user and are read and dispatched from the event loop to widgets by the user interface thread. Application code registers interest in events by adding event listeners to widgets. This code is invoked in response to an event when it is dispatched. Thus, the event loop is running application code, as well as dispatching operating system events. If the user interface thread is busy running code and does not call readAndDipatch() when the user generates an event, the event is queued. When readAndDispatch() is called, outstanding events that the user has generated are delivered. If you do not call readAndDispatch(), events will never be delivered, your program will appear hung, and the user will eventually terminate it. Calling readAndDispatch() indicates that the user interface thread is at a clean point, ready to process an operating system event. At that time, by definition, the user interface thread is not busy running a widget operation or listener. Thus, it is ready to safely run timers that have expired or arbitrary code on behalf of other threads resulting from calls to syncExec() or asyncExec().
The fact that events from the user and operating system, timers, and syncExec() and asyncExec() runnables can be generated at any time but are delivered to your program only when you call readAndDispatch() makes your multithreaded program more deterministic.
Up to this point, we have been discussing listeners and the event loop. As mentioned previously, Display also provides many other utility functions.
|