Threads
By default, any interface definition executes within a single thread, and since currently
GUIKit` definitions execute at runtime as Java components, this means that execution occurs in the single Java AWT event dispatch thread.
In most cases, complete user interface dialogs or tools can run within a single Java thread, make synchronous requests to
Mathematica, and never require any explicit threading code to handle how requests are processed. Also note that since the
Mathematica kernel is not multithreaded, the only reason for attempting a multithreaded interface definition is to allow user interface updates to occur while a long calculation may be proceeding in
Mathematica.
Consider, for example, the following definition.
Take a screen shot of what this definition renders.
If you try running this example and pressing the button, you will not actually see the label's text update at all. Why is this? The reason is that the button's bind event is executing in the default single AWT thread, and while it is executing (during its action call), the user interface is busy while all the attempts at setting the label's text are occurring from the
Script code. The user interface thread is busy evaluating the button action call and is not receptive to any other requests to update the label's text and repaint the window. If you want to see the user interface update while a possibly long
Mathematica calculation is going on, you would need to have the
BindEvent code execute in a new thread asynchronously, so that the user interface event dispatching thread is not busy and can take requests for updating other user interface widgets. However, there is an important subsequent requirement that needs to be satisfied. User interface widgets cannot be updated from calls in any other threads but the AWT event dispatching thread, so requests for updating widgets, such as through
SetPropertyValue, must be made and queued for execution on the AWT event dispatching thread.
GUIKit attempts to simplify issues related to spawning execution in new separate threads and also makes sure certain executions happen on the AWT event dispatch thread when this is required. Many of the execution functions in
GUIKit, such as
BindEvent,
SetPropertyValue, and
InvokeMethod, take two optional options:
InvokeThread -> "Name", which chooses which thread a snippet of code will execute in, and
InvokeWait -> Automatic | True | False, which determines whether the thread that initiates this new request, possibly in a different thread, will wait for the response from this new request to finish before continuing, or whether it ignores any response and immediately continues with its execution.
InvokeThread currently accepts the following three values:
"Current" (the default),
"New", or
"Dispatch". The choice of
"Current" makes no attempt to create a new thread to execute the request in and operates within the same current active thread.
"New" will create a new thread and execute the code within this new thread.
"Dispatch" requests that the code execute within the AWT event dispatching thread. The default value for
InvokeWait is
Automatic and the default behavior is based on the value of
InvokeThread, if an explicit setting of
InvokeWait is not included. The following table summarizes the default automatic behavior of
InvokeWait.
| | | |
| Current | Any | True | execution occurs on the current thread synchronously waiting for the result of the code before continuing |
| New | Any | False | execution is occurring in a new thread and by default the code will not wait for a response before continuing |
| Dispatch | Dispatch | True | if you request the Dispatch thread, and you are currently running in the Dispatch thread, the response will be returned synchronously |
| Dispatch | not Dispatch | False | if you are not already in the Dispatch thread, asynchronously have the execution queued to occur on the dispatch thread as soon as possible without waiting for the response |
Using the
InvokeThread option and the default behavior of
InvokeWait, you can now thread the execution of the
Mathematica calculation using a new thread on the
BindEvent and update the user interface in the event dispatch thread when calling
SetPropertyValue.
Notice also the desire to disable the button while the execution is threaded since
Mathematica cannot evaluate requests from multiple threads, and allowing another request can lead to unpredictable results in the kernel evaluation sequences.
For a more detailed description of issues related to using Java user interfaces in a multithreaded environment, see Sun's Java documentation.