tags:

views:

511

answers:

3

I deployed a MATLAB project into a DLL, to be called from C++, and it works just fine. Happy days.

But what happens when the user asks to cancel an operation?

I tried creating a global variable named UserAborted. I initialize it to 0 before running the long function in MATLAB. I also wrote the following two functions:

function AbortIfUserRequested
    global UserAborted

    if (UserAborted == 1)
        error('User Abort');
    end
end

function UserAbortLongFunction
    global UserAborted

    UserAborted = 1;
end

I call upon AbortIfUserRequested in every iteration of the loop in my long function. I also exported UserAbortLongFunction.

I expected that pretty soon after called UserAbortLongFunction, the long function would reach a call to AbortIfUserRequested, and throw an error.

Instead, the long function keeps running until the end, and only then does the value of UserAborted get changed.

All I want to do is abort that long function when the user asks me to! Is there any way to do that?

+1  A: 

Matlab needs to provide callback functions to show execution progress and possibly halt it. A Google search shows lots of people wanting this but no implementation from Mathworks.

whatnick
Hmm... Good point. But you know, MATLAB does have a couple of callback functions - for reporting standard output and standard error. I just did `disp('PROGRESS=33%)` and that called the callback function for handling standard error. Then I just parsed those strings, and displayed the progress in the C++ GUI. But you're right - there's no proper support.
scraimer
+1  A: 

Matlab's single-threaded nature might be preventing the update to the global variable's value from propagating while the first function is executing. You could try sticking the abort flag in a Java object, like a HashMap, for a layer of indirection. Since Java objects are passed by reference, an update to its state may be visible immediately, without requiring a change to the Matlab variable itself.

Here's a snippet to do so. (Sorry, I don't have a Matlab Compiler license to test this out in a deployed DLL.)

function AbortIfUserRequested
    global SharedState
    if SharedState.get('UserAborted')
        error('User Abort');
    end
end

function UserAbortLongFunction
    global SharedState
    SharedState.put('UserAborted', 1);
end

function InitUserAbort
    global SharedState
    SharedState = java.util.Collections.synchronizedMap(java.util.HashMap());
    SharedState.put('UserAborted', 0);
end

Matlab app data is also effectively passed by reference. Putting the abort flag in appdata instead of a global variable might work, too. If your library works with a Matlab GUI, you can put the app data on its figure handle instead of the global handle 0. This would be more idiomatic Matlab than the Java object, if it works.

function AbortIfUserRequested
   if getappdata(0, 'UserAborted')
      error('User Abort');
   end
end
function UserAbortLongFunction
   setappdata(0, 'UserAborted', 1);
end
Andrew Janke
+4  A: 

Try calling the DRAWNOW function in AbortIfUserRequested. Although Matlab is single-threaded (from an API perspective), it does allow for interrupts. I've had success by calling this function with pure M-code where user input (like Ctrl-C) otherwise gets locked out.

Mr Fooz