It often happens that we need our program to wait for some condition to occur. This condition may depend on some external process that updates the condition asynchronously, meaning in a non-predictable (non-specific) time. A typical example is user mouse or keyboard actions in a GUI dialog window, or a specific signal that is received from hardware.
waitfor and other built-in functions
Matlab has a couple of built-in functions for blocking Matlab’s main processing thread until certain asynchronous GUI events occurs. waitfor is documented to block code execution until either the specified GUI handle object is deleted, or is updated (possibly to a specified value), or Ctrl-C is pressed in matlab’s Command Window. uiwait similarly blocks execution, until a specified figure handle is deleted/closed, or a separate processing thread (typically, a callback function) calls the corresponding uiresume (I discussed uiwait/uiresume, together with their uisuspend/uirestore siblings, last year). uiwait, unlike waitfor, has an optional timeout parameter; on the other hand, uiwait cannot wait for a non-deletion event on a regular uicontrol property, as waitfor can.
Other related built-in Matlab functions are waitforbuttonpress, pause (which awaits user mouse/keyboard clicks), and ginput, gtext, rbbox, dragrect (which awaits mouse clicks in a plot/image axes). Some toolboxes have other similar blocking functions, for example roipoly in the Image Processing toolbox.
Waiting for events on non-HG objects
But what if we need to wait for an event to happen on a non-Matlab (HG) object? Say on an ActiveX control property or even on a non-graphical Java object?
It turns out that waitfor can also be used in these cases. Although not documented, waitfor actually accepts handles not only of HG objects (e.g., figure handles) but also of other types of handles, such as regular Java reference handles. The usage is the same as for regular HG handles:
waitfor(objectHandleOrReference, 'propertyName', propertyValue);
For example, to wait for data to be available in a
java.util.Hashtable object, which has a public boolean isEmpty() method and therefore returns a value of ‘on’ or ‘off’ for get(object,’Empty’):
waitfor(javaHashTableReference, 'Empty', 'off');
(Note that Matlab automatically converts a Java
boolean into ‘on’/’off’ in such cases, so we need to use ‘on’/’off’ rather than true/false; this is not always the case – a counter-case is presented immediately below)
Setting a timeout on waitfor
To set a timeout on our blocked wait, a feature of uiwait that is missing in the built-in waitfor, we can use a dedicated one-time timer object. Timer callbacks use a separate thread from the main Matlab processing thread, and are therefore processed even when the Main thread is blocked. The implementation is quite easy, as shown below:
% Wait for data updates to complete (isDone = false if timeout, true if data ok) function isDone = waitForDone(object,timeout) % Initialize: timeout flag = false object.setDone(false); % Create and start the separate timeout timer thread hTimer = timer('TimerFcn',@(h,e)object.setDone(true), 'StartDelay',timeout); start(hTimer); % Wait for the object property to change or for timeout, whichever comes first waitfor(object,'Done',true); % waitfor is over - either because of timeout or because the data changed % To determine which, check whether the timer callback was activated isDone = (hTimer.TasksExecuted == 0); % Delete the time object try stop(hTimer); catch, end try delete(hTimer); catch, end % Return the flag indicating whether or not timeout was reached end % waitForDone
In some cases (for example, waiting on a specific field value within a struct, which waitfor does not support), we need to revert to using plain-ol’ polling, rather than the more efficient blocked wait. In such cases, I strongly advice to place a certain pause within the polling loop:
delay = 0.01; % 10 milliseconds while ~object.isDone % set by the callback pause(delay); % a slight pause to let all the data gather end
Or, a variant with timeout:
delay = 0.01; for idx = 1 : (timeout/delay) % wait up to N secs before giving up if object.isDone % set by the callback break; end pause(delay); % a slight pause to let all the data gather end
The reason we need this deliberate pause is to enable the CPU to process other processing threads, namely that thread which is responsible for updating the field value in due time. Without this pause, it would take the CPU much longer (if at all) to get to that thread, and our overall application performance will actually degrade, since the event will take longer to get processed.
Adding deliberate pause delays as a mechanism to improve overall performance may sound counter-intuitive, but this is in fact the case here. Performance tuning can indeed be counter-intuitive sometimes, until you learn the underlying reasons when it becomes clear (I’ve shown several examples of this in the past, here, here, here and here).
We should take care not to set too high a pause delay, since that will unnecessarily delay processing of the incoming event; on the other hand, setting it too low will return the thread-starvation issue explained above. A pause value of 5-50 millisecs (0.005-0.05) should be about right for the vast majority of applications. Note that different platforms run your application at different speeds, so be careful not to over-tune this delay to a particular computer.
Interested in learning more Matlab performance or advanced programming tricks? Then consider joining my Matlab Performance Tuning, Advanced Matlab GUI and/or Matlab-Java programming seminars in Geneva on August 21-23, 2012 – email me (altmany at gmail dot com) for details.