Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Controlling callback re-entrancy

August 10, 2011 17 Comments

I’d like to welcome guest blogger Malcolm Lidierth of King’s College London. Malcolm is well known in the Matlab-Java community for his jcontrol utility. Some months ago, I mentioned his work on another File Exchange contribution, MUtilities when I discussed transparent Matlab figure windows. Today, Malcolm discusses one of his lesser-known but extremely important isMultipleCall utility.
Every now and again, a very simple bit of code turns out to be more useful than the author initially imagined. Something I have repeatedly used is the isMultipleCall function which I posted to MATLAB Central’s File Exchange a year or so ago.
The isMultipleCall function uses fully-documented pure-MATLAB to extend the control that can be achieved over callbacks.
Here was the problem: I had a modular system built in MATLAB which allowed third-party developers to add their own plugins. I wanted a mechanism to force the dismissal (“bail-out”) of a callback even when the Interruptible property of the parent object was set to ‘on’. Such callback re-entrancy issues are common for rapidly-firing events, and debugging and fixing them is usually not easy.
The callback’s dismissal code would need to be fast because it might be called many dozens of times, e.g. in a WindowButtonMotion callback. An obvious approach was to check the function call stack using MATLAB’s dbstack function. Although, at first, this seemed likely to be too slow, profiling showed it was not – taking < 40µsec per call – and within a WindowButtonMotion callback in a real GUI, I could not perceive any slowing of the code.
Here is the function:

function flag=isMultipleCall()
  flag = false;
  % Get the stack
  s = dbstack();
  if numel(s)< =2
    % Stack too short for a multiple call
    return
  end
  % How many calls to the calling function are in the stack?
  names = {s(:).name};
  TF = strcmp(s(2).name,names);
  count = sum(TF);
  if count>1
    % More than 1
    flag = true;
  end
end

function flag=isMultipleCall() flag = false; % Get the stack s = dbstack(); if numel(s)< =2 % Stack too short for a multiple call return end % How many calls to the calling function are in the stack? names = {s(:).name}; TF = strcmp(s(2).name,names); count = sum(TF); if count>1 % More than 1 flag = true; end end

With isMultipleCall invoked from another function (see note below), dbstack will return a structure with a minimum of 2 elements – the first relating to isMultipleCall itself and the second to the calling function. So with numel(s) <= 2, there can be no multiple calls and we can return false immediately thus saving time in doing any further testing. For numel(s) > 2 we simply check to see whether the calling functions referenced in s(2) appears anywhere else on the stack. If it does, then we return true; otherwise false.
Then, in our callback code we simply use:

if isMultipleCall();  return;  end

if isMultipleCall(); return; end

If this line is placed first in the callback function code, it essentially mimics the behavior that you might expect after setting the Interruptible property of the event firing object to ‘off’. Adding a drawnow() at the end of the callback will ensure that any waiting callbacks in the queue are dismissed:

function MyCallback(hObj, EventData)
  % Quick bail-out if callback code is called before another has ended
  if isMultipleCall();  return;  end
  ...  % do some actual callback work here
  drawnow();
end

function MyCallback(hObj, EventData) % Quick bail-out if callback code is called before another has ended if isMultipleCall(); return; end ... % do some actual callback work here drawnow(); end

There are several ways in which isMultipleCall can extend the standard MALAB functionality. First, by moving isMultipleCall reference from the first line of the callback we can create both an interruptible and an uninteruptible code block, e.g.

function MyCallback(hObj, EventData)
  %Code Block 1
  ...
  if isMultipleCall();  return;  end
  %Code Block 2
  ...
  drawnow();
end

function MyCallback(hObj, EventData) %Code Block 1 ... if isMultipleCall(); return; end %Code Block 2 ... drawnow(); end

Second, as isMultipleCall controls the callbacks – not the objects that trigger them – we can individually control the callbacks of objects which fire multiple events. That is particularly useful with Java components, which gives a third extension – isMultipleCall can be used in any function: not just the callbacks of standard MATLAB components, but also of Java or COM components.
 
Finally, as the callback, not the object is being controlled, we can control a callback that may be shared between multiple objects e.g. a menu component and a toolbar button.
Not bad for 13 lines of code.
Note: isMultipleCall must be called from a function, not from a string in the callback property.
Do you have any other favorite mechanism for controlling callback re-entrancy? If so, please post a comment.

Related posts:

  1. Callback functions performance – Using anonymous functions in Matlab callbacks can be very painful for performance. Today's article explains how this can be avoided. ...
  2. Continuous slider callback – Matlab slider uicontrols do not enable a continuous-motion callback by default. This article explains how this can be achieved using undocumented features....
  3. Controlling plot data-tips – Data-tips are an extremely useful plotting tool that can easily be controlled programmatically....
  4. Inactive Control Tooltips & Event Chaining – Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
  5. Java stack traces in Matlab – Matlab does not normally provide information about the Java calls on the stack trace. A simple trick can show us this information....
  6. Matlab and the Event Dispatch Thread (EDT) – The Java Swing Event Dispatch Thread (EDT) is very important for Matlab GUI timings. This article explains the potential pitfalls and their avoidance using undocumented Matlab functionality....
Callbacks COM Java Malcolm Lidierth Pure Matlab
Print Print
« Previous
Next »
17 Responses
  1. Mikhail August 10, 2011 at 12:44 Reply

    My approach is instead of calling

    varargout = func( varargin )

    varargout = func( varargin )

    inside of callback, use following syntax:

    varargout = func_queue( @func, varargin )

    varargout = func_queue( @func, varargin )

    where function

    func_queue()

    func_queue()

    is responsible for interrupting if called multiple times and always caching last varargin so that it is not getting lost.

  2. Arda August 11, 2011 at 07:30 Reply
    persistent returnFlag
    if ~isempty(returnFlag)
       return
    end
    returnFlag=1;
    ...do something
    returnFlag=[];

    persistent returnFlag if ~isempty(returnFlag) return end returnFlag=1; ...do something returnFlag=[];

    6 lines 🙂

  3. Malcolm Lidierth August 11, 2011 at 14:58 Reply

    @Arda – that’s certainly faster by about 10-fold, but would be less easy to maintain e.g. with multiple return points. Perhaps the challenge should be to achieve this with less than one line in the callback!

    • Arda August 12, 2011 at 11:20 Reply

      @Malcolm, it was just a joke. Sorry for the misunderstanding. Yet the code i wrote above does not work as i suspected..

    • Malcolm Lidierth August 12, 2011 at 12:50 Reply

      @Arda
      Your code worked for me in a WindowButtonMotionFcn relacing …doSomething with

       line(rand(1,10),rand(1,10));
      drawnow();

      line(rand(1,10),rand(1,10)); drawnow();

      That example simulates the effect of setting ‘Interruptible’ to ‘off’ and ‘BusyAction’ to ‘cancel’ – but via the callback rather than the object. If isMultipleCall() took up a large proportion of the execution time, an approach like this would be far better – the processor overhead for your code is tiny. Another tack is to clear the callback property at the start and reset it at the end of the callback routine – but if any error or ^C occurs while its cleared how would you reset it?

      • Yair Altman August 13, 2011 at 15:15

        @Malcolm, you cannot clear the callback property value from within an executing callback, AFAIK. At least, it didn’t work a few releases ago and since it made sense I did not try again lately. The property appears to change, but then reverts to its previous value when the callback ends.

    • Malcolm Lidierth August 14, 2011 at 07:26 Reply

      @Yair
      That surprises me. You certainly can with a figure WIndowButtonMotion callback The code below runs just once after using set(figH, ‘WindowButtonMotionFcn’, @MyCallback).

      function MyCallback(hObject, EventData)
      set(hObject, 'WindowButtonMotionFcn', []);
      disp('In Callback');
      return
      end

      function MyCallback(hObject, EventData) set(hObject, 'WindowButtonMotionFcn', []); disp('In Callback'); return end

    • Christos Oreinos March 7, 2017 at 18:32 Reply

      I also used a solution almost similar to Arda’s (using a persistent variable). After reading this post I opted for the isMultipleCall() because, like Malcolm very very wisely says, I had problems when internal callback errors (which were not fatal in my case) or Ctrl+C stopped the callback that I was controlling for recursive call. In this case the callback could not be run again unless I explicitly cleared all variables.

  4. Arda August 20, 2011 at 12:40 Reply

    By the way, if the handle has properties ‘BusyAction’ and ‘Interruptable’ (like figure windows, uicontrols, etc.), setting ‘cancel’ and ‘off’ is always a choice. That should do the same…

  5. Michele February 2, 2012 at 01:31 Reply

    This utility is very interesting, but due to the use of ‘dbstack’ it wouldn’t work in compiled applications.
    Do you know of any easy workaround for that?
    Thank you very much

    • Yair Altman February 2, 2012 at 01:42 Reply

      @Michele – you could store a temporary flag in a persistent variable or the handle’s ApplicationData/UserData, or a variant of these. For example:

      % Variant1
      function myCallbackFcn1(hObject,eventData,varargin)
         persistent inCallback
         if ~isempty(inCallback),  return;  end
         inCallback = true;
         try
             % do something useful here
         catch
             % error trapping here
         end
         pause(0.001); drawnow;  % give all other events a chance to bail out above
         inCallback = [];
      end  % myCallbackFcn1
       
      % Variant2
      function myCallbackFcn2(hObject,eventData,varargin)
         inCallback = getappdata(hObject,'inCallback');
         if ~isempty(inCallback),  return;  end
         setappdata(hObject,'inCallback',true);
         try
             % do something useful here
         catch
             % error trapping here
         end
         pause(0.001); drawnow;  % give all other events a chance to bail out above
         setappdata(hObject,'inCallback',[]);
      end  % myCallbackFcn2

      % Variant1 function myCallbackFcn1(hObject,eventData,varargin) persistent inCallback if ~isempty(inCallback), return; end inCallback = true; try % do something useful here catch % error trapping here end pause(0.001); drawnow; % give all other events a chance to bail out above inCallback = []; end % myCallbackFcn1 % Variant2 function myCallbackFcn2(hObject,eventData,varargin) inCallback = getappdata(hObject,'inCallback'); if ~isempty(inCallback), return; end setappdata(hObject,'inCallback',true); try % do something useful here catch % error trapping here end pause(0.001); drawnow; % give all other events a chance to bail out above setappdata(hObject,'inCallback',[]); end % myCallbackFcn2

      • Michele February 2, 2012 at 01:49

        @Yair – Thank you very much for the quick reply, I’ll definitely give it a try.

  6. Rafael May 31, 2013 at 15:58 Reply

    This is very interesting. But how would you handle the case when you don’t want to bail out of the callback if it’s already executing, but you want to wait instead for the first instance to finish? The obvious solution of putting a polling loop does not work because the loop will keep Matlab from finishing the execution of the first instance. I can’t seem to find a solution to that problem!
    Thanks!

    • Yair Altman June 1, 2013 at 10:41 Reply

      @Rafael – if the callback’ed object supports the BusyAction and Interruptable properties, then setting these would be the easiest choice. Otherwise, you could preserve the callback parameters in some persistent data struct (e.g., a cell array) and set a timer object to run the callback function programmatically in a second or two.

  7. Rafael June 3, 2013 at 13:56 Reply

    Thanks a lot for the answer @Yair!
    I’m not sure your solution of using a timer to re-execute the function will work for me. I have thought of that solution for a while, but let’s say you have two things that must happen in a particular order, and only the first one is the one that must be re-executed by the timer. How do I hold the execution of the second process until the first one has for sure executed? I get back to the polling loop problem! Would I have to convert all of my processes into timers that are constantly firing to check if it’s OK to execute in the right order? My whole system would be come a nightmare if I have to do that!

  8. Elliott February 20, 2014 at 14:18 Reply

    This has been a really useful post and has really helped out a Matlab GUI that I have.

    I’m confused on one count though, and I’m sure this is just my lack of understanding of how Matlab runs behind the scenes. Why does this not work with a figure’s ResizeFcn callback? I would really like to have a custom resize, but it needs to be safe against re-entrancy. Currently, I’d handle this with a timer, but I’d rather not have to use that.

    Is there a way to get this to work with the ResizeFcn?

    Thanks.

  9. Jan July 29, 2020 at 20:13 Reply

    Is there a reason why this function was removed from the Matlab File Exchange?

    I prefer a simplified DBSTACK solution:

    function flag = isMultipleCall()
       s = dbstack();
       flag = (numel(s) > 2) && (sum(strcmp(s(2).name, {s.name})) > 1);
    end

    function flag = isMultipleCall() s = dbstack(); flag = (numel(s) > 2) && (sum(strcmp(s(2).name, {s.name})) > 1); end

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top