Is there a way to know when an MATLAB exits? I wanted to do some work, for example, release some resource, print some logs... I could add some code at some class's destructors. But since we cannot determine the order that MATLAB calls destructors, I am not sure which one is the last one so I can release the resource.
Can we register any callback to the MATLAB exit event if there exists such an event...?
There is no exit event I know of that's thrown when exiting from a function or MATLAB itself. However, there are two things you can do to handle final cleanup:
Use onCleanUp objects: When exiting from a function, variables in the local workspace are destroyed (and exiting from MATLAB itself will destroy objects in the base workspace). When working with resources (files, etc.), good practice is to create an onCleanUp object to handle those resources in an exception-safe manner. This is discussed in more detail in the documentation and this question: How do you handle resources in MATLAB in an exception safe manner? (like “try … finally”)
Create a finish.m file: When quitting MATLAB, it will look on the search path for a file named finish.m and run that code before terminating.
You can place any cleanup actions in the finish.m file.
Similar to startup.m, MATLAB executes this file (when found on the MATLAB search path) just prior to program termination.
Also worth looking into is onCleanup. This simple class creates an object that, when destroyed, runs the function registered during object creation. This is extremely useful when dealing with files for example:
fid = fopen(filename, 'r');
OC = onCleanup(#() any(fopen('all')==fid) && fclose(fid));
% ...file reading and processing here
% ERROR HAPPENS HERE!
% ... more processing here
fclose(fid);
meaning, the file handle fid is still closed, even though the normal fclose(fid) was not reached. This is because the object OC was cleared implicitly by MATLAB after the error.
Related
Does the execution of addpath/rmpath/savepath in one MATLAB instance affect other instances?
Motivation: Imagine that you are developing a MATLAB package, which provides a group of functions to the users. You have multiple versions of this package being developed on a single laptop. You would like to test these different versions in multiple instances of MATLAB:
You open one MATLAB window, type run_test(DIRECTORY_OF_PACKAGE_VERSION1), and hit enter;
While the first test is running, you open another MATLAB window, type run_test(DIRECTORY_OF_PACKAGE_VERSION2), and hit enter.
See the pseudo-code below for a better idea about the tests.
No code or data is shared between different tests --- except for those embedded in MATLAB, as the tests are running on the same laptop, using the same installation of MATLAB. Below is a piece of pseudo-code for such a scenario.
% MATLAB instance 1
run_test(DIRECTORY_OF_PACKAGE_VERSION1);
% MATLAB instance 2
run_test(DIRECTORY_OF_PACKAGE_VERSION2);
% Code for the tests
function run_test(package_directory)
setup_package(package_dirctory);
RUN EXPERIMENTS TO TEST THE FUNCTIONS PROVIDED BY THE PACKAGE;
uninstall_package(package_directory);
end
% This is the setup of the package that you are developing.
% It should be called as a black box in the tests.
function setup_package(package_dirctory)
addpath(PATH_TO_THE_FUNCTIONS_PROVIDED_BY_THE_PACKAGE);
% Make the package available in subsequent MATLAB sessions
savepath;
end
% The function that uninstalls the package: remove the paths
% added by `setup_package` and delete the files etc.
function uninstall_package(package_directory)
rmpath(PATH_TO_THE_FUNCTIONS_PROVIDED_BY_THE_PACKAGE);
savepath;
end
You want to make sure the following.
The tests do not interfere with each other;
Each test is calling funtions from the correct version of the package.
Hence here come our questions.
Questions:
Does the execuation of addpath, rmpath, and savepath in one MATLAB instance affect the other instance, sooner or later?
More generally, what kind of commands executed in one MATLAB instance can affect the other instance?
3. What if I am running only one instance of MATLAB, but invoke a parfor loop with two loops running in parallel? Does the execution of addpath/rmpath/savepath in one loop affect the other loop, sooner or later? In general, what kind of commands executed in one parallel loop can affect the other loop? (As pointed out by #Edric, this can be complicated; so let us not worry about it. Thank you, #Edric.)
Thank you very much for any comments and insights. It would be much appreciated if you could direct me to relevant sections in the official documentation of MATLAB --- I did some searching in the documentation, but have not found an answer to my question.
BTW, in case you find that the test described in the pseudo code is conducted in a wrong/bad manner, I will be very grateful if you could recommend a better way of doing it.
The documentation page for the MATLAB Search Path specifies at the bottom:
When you change the search path, MATLAB uses it in the current session, but does not update pathdef.m. To use the modified search path in the current and future sessions, save the changes using savepath or the Save button in the Set Path dialog box. This updates pathdef.m.
So, standard MATLAB sessions are "isolated" in terms of their MATLAB Search Path unless you use savepath. After a call to savepath, new MATLAB sessions will read the updated pathdef.m on startup.
The situation with a parallel pool is slightly more complex. There are a couple of things that affect this. First is the parameter AutoAddClientPath that you can specify for the parpool command. When true, an attempt is made to reflect the desktop MATLAB's path on the workers. (This might not work if the workers cannot access the same folders).
When a parallel pool is running, any changes to the path on the desktop MATLAB client are sent to the workers, so they can attempt to add or remove path entries. Parallel pool workers calling addpath or rmpath do so in isolation. (I'm afraid I can't find a documentation reference for this).
My matlab program is a multiple window programmatic GUI. I have implemented a reporting system so when an error is encountered, it calls a function I wrote, generateReport.m, which sends an e-mail with some log and state info and then continues execution.
To accomplish this I have put a try-catch block in EVERY single function. That means even creating a wrapper for my main function. Does anybody know of a way to avoid this? I.e. being able to but a global try-catch. The reason I need multiple try-catch blocks right now is because try-catch will catch errors in functions within the block, but not sub-functions of those
Example psuedo-code:
try:
segmentImage
catch:
generateReport
end
^-- This way an error in segment-image calls generateReport, however an error in a subfunction of segment-image won't. Optimally I would only need one try-catch (or some other statement/structure I'm not aware of) in each file.
Most of the files code one GUI window each. Some are just utility.
I wrote a similar question before: matlab can't catch error in subfunction
That question asked how to use the try-catch or some function-wrapper in a callback, to implement the reporting system I have now. Before I just wanted to know why I couldn't catch errors in subfunctions. I put try-catches in every subfunction to solve that.
This question is different as I'm asking is if there's another way to do this instead of putting a try-catch in every function and subfunction which is really inconvenient and doesn't look that great. Maybe a technique I don't know about to do this or a more efficient way of structuring my code to accomplish this is needed?
Example of multiple try-catches:
First the main function I run, which just wraps CSTMainWindow
function CeleST
try
% Global try-catch on CeleST
CSTMainWindow()
catch exception
generateReport(exception)
end
Within CSTMainWindow: I have to put try-catch blocks on it's subfunctions. In this example given CSTProcessVideos and CSTCheckResults are programmatic GUI files
function processVideo(hObject,eventdata) %#ok<INUSD>
try
set(mainFigure,'Visible','off');
CSTProcessVideos
set(mainFigure,'Visible','on');
flagConsistentButton = false;
checkSequences
populateFilters
catch exception
generateReport(exception)
end
end
function checkResults(hObject,eventdata) %#ok<INUSD>
try
set(mainFigure,'Visible','off');
CSTCheckResults
set(mainFigure,'Visible','on');
flagConsistentButton = false;
checkSequences
populateFilters
catch exception
generateReport(exception)
end
end
I would like to know if there's something I could do to avoid putting a try-catch on everything (I also put the try-catch blocks on subfunctions that don't contain code written in other files)
I hope my question was clear. Thanks in advance for the help
Preliminaries. Since your application is event-driven (i.e. performs actions by callbacks) you have at least two potential sources of errors: 1) the function that builds your GUI, and then exits, 2) every callback assigned to the active UI elements.
The GUI builder. Errors in building the GUI should exit the application. Which means that your function should look like
function main(arg1, arg2, ...)
try
% test your arguments
% create the main window
% add ui elements
% register the callbacks
% create backup for application state
catch ME
generateReport(ME);
end;
end
without putting a try/catch in every helper function that is called. Since the GUI creation is faulty, the catch block should not attempt to restore the application to a (safe) default state, because there is no such default state to begin with.
The callbacks. Errors in callbacks are most likely due to wrong user input, so there is a way to rollback the application to the last known safe state:
function ui1_cbk(h, varargin)
try
% test your arguments
% perform required action
% update the backup state with the actual state
catch ME
generateReport(ME);
% restore state from last good backup
% let the user know something went wrong
end;
end
function ui2_cbk(h, varargin)
try
% ...
catch ME
% ...
end;
end;
Please note that, for UI elements that have a single callback registered to them, there is one easy way to handle all actions in a single function, thus having a single try/catch block:
function ui_general_cbk(h, varargin)
try
switch get(h, 'Tag')
case 'Tag_ui1'
% test your arguments
% perform required action
case 'Tag_ui2'
% test your arguments
% perform required action
% ...
otherwise
% ignore request
end;
% update the backup state with the actual state
catch ME
generateReport(ME);
% restore state from last good backup
% let the user know something went wrong
end;
end
Of course, for this to work, your GUI builder should assign unique (and maybe suggestive) tags to all your active UI elements.
How to generate error reports. The try/catch block could be only at the top level of the main function and the callback; to see what exactly caused the exception, one can always inspect the .stack struct array of the ME object, and—for fancy exception handling—eventually the .cause field (which would be another MException object if not empty). Like this one avoids polluting all the functions with exception handling on every level.
I have a script that calls a function, which is written in separate file and contains sub-functions that are inner to main function only. In one of my sub-functions, I have persistent variable that I would like to clear every time I run the main script. How can I do so? In addition, I have breakpoints through my code, and I would prefer to keep them while I clear the persistent variable - how that can be done?
MainScript.m script:
clear variables;
for iterNum=1:5
dataOut = MyMainFunction(iterNum);
end
disp(dataOut);
MyMainFunction code:
function dataOut = MyMainFunction(iterNum)
if (iterNum==1)
clear MySubFunction;
end
dataOut = MySubFunction();
end
function dataOut = MySubFunction()
persistent idx;
if isempty(idx)
idx=1;
end
dataOut=idx;
idx=idx+1;
end
I would like to clear "idx" persistent variable every time that I run MainScript.m, but of course to keep that variable as long as the script is running.
Thanks, John
The easiest way I see is to call clear followed the function name:
clear MySubFunction
instead of
clear variables;
This should clear all the persistent variables in that particular function. This will probably have the side effect of removing the stored JIT'd copy of it, causing it to be reparsed the next time it is invoked.
You can use munlock if you previously mlock'ed your function.
OR
You can define a special set of parameters in your function that are designed to solely clear the persistent variable, and you call the function with this syntax at the beginning of your main file.
Unfortunately, the other answer is partially incorrect - it is NOT possible to clear persistent variables in a sub-function using clear MySubFunction.
To quote an answer by a MathWorks staff member,
Only top level or main functions (with the same name as the file) may be cleared. To clear any local or nested function the main function must be cleared and that can't be done while the main function (or any other function in the file) is running.
and
Only whole m files can be cleared from memory. The entire file is managed as a unit so sub functions can't be cleared without clearing the main function.
As such, your options are to
separate the sub-function into its own m-file, or
clear the entire MyMainFunction from within MainScript.m, or
follow Ratbert's second suggestion, i.e. instead of using clear, give MySubFunction an additional argument that tells it to reset the persistent variables by itself
tl;dr
Is there any way in a Matlab .m file to detect that Matlab termination is under way?
I have an unmanaged library that provides an interface to my product. I have wrapped that for Matlab using a mex file. So my unmanaged library exists as a Windows DLL. I have a mex file that wraps that. In turn I have a collection of Matlab classes, implemented in various .m files that wrap the mex file. So far so good, all of this works splendidly.
I recently became aware of a problem during Matlab shutdown. Some of the Matlab classes wrap unmanaged objects. These unmanaged objects need to be destroyed when they are no longer needed. So I implement delete functions for the Matlab classes that wrap the unmanaged objects, and call into the mex file to destroy the objects. Obviously the mex file simply forwards these destruction calls to the unmanaged library. Again, this all works just fine.
The problem arises when Matlab shuts down and the user's workspace contains Matlab objects wrapping the unmanaged objects. Unfortunately, Matlab unloads the mex file, and then destroys the objects in the workspace. What happens next is that the delete function executes which calls into the mex file. Which reloads the mex file that was just unloaded. And now the attempt to destroy the unmanaged object leads to runtime errors, because my library has to be re-loaded.
Since is going to unload the mex file before destroying workspace objects, I have no choice but to skip the deletion of the unmanaged objects in that scenario. It isn't a memory leak or indeed a problem in any way, since the process is terminating. However, I do need to detect that the process is terminating. Which leads to the question, how to do that.
I'm aware of the finish.m termination file, but I'm not in control of that since I am providing a library. The user controls their termination file, and so I've ruled out that option. I don't even know whether or not it runs at a suitable time, i.e. before the workspace objects are destroyed.
I've built a functioning solution using mexAtExit. In the mex file initialization I call mexAtExit like so:
mexAtExit(atExit);
The atExit function is:
void atExit(void)
{
mexCallMATLAB(0, NULL, 0, NULL, "mylib.atExit");
}
And ofx.atExit is in the Matlab code and is implemented like this:
methods(Static)
function atExit
mylib.mexHasUnloaded(true);
end
function result = mexHasUnloaded(varargin)
global mexHasUnloadedGlobalVar;
if isempty(mexHasUnloadedGlobalVar)
mexHasUnloadedGlobalVar = false;
end
if nargin > 0
mexHasUnloadedGlobalVar = varargin{1};
end
result = mexHasUnloadedGlobalVar;
end
....
end
The delete function then checks mexHasUnloaded like this:
function delete(self)
if ~mylib.mexHasUnloaded
mylibMex(mylib.mexDestroyObject, self.handle);
end
end
Whilst this appears to work, I'm not at all happy with it.
Can I really only detect Matlab termination from inside a mex file? I would like to detect this directly in the .m file and it feels like that ought to be possible. Is it possible?
Do I really need to use a global variable like that? Can't I find a better way to look after this state? I tried using a persistent variable but that was just as hacky and did not work. The persistent variable was re-initialised at some point during the termination which meant that mexHasUnloaded started returning false after it had earlier been set to true.
Or is there a different solution to my problem? Can I force my mex file to stay loaded until after the workspace objects are deleted?
Does it work to mexLock() your MEX file so that it doesn't get unloaded, so the delete methods can do the right thing at shutdown?
I've looked through the documentation, etc, but I'm not seeing anything obvious. I'd like to have a signal handler that can intercept ^C, ^\, or some other keypress that could be used to interrupt a long-running script (each discrete computation is typically <1s) and allow it to exit gracefully and save current state.
Matlab does have event handlers for COM, but it's windows-only and I'm in a *nix environment.
If the answer is 'tough luck', I'm cool with that ... I'm just not seeing anything that says I'm SOL yet.
MATLAB already interprets ^C as an interrupt. You can use onCleanup objects to ensure that your program state is preserved correctly. I.e. something like:
function testFcn
x = onCleanup( #() disp('perform cleanup here...') );
for ii=1:1000, disp(ii), pause(1), end
Run the above and hit ^C when you get bored. Obviously, you can hook any function handle in to your onCleanup object. See also the reference page for onCleanup.