Wait a boolean variable becomes false

I have connected the software Plant Simulation to Matlab and thus when I start the matlab program the simulation on Plant SImulation correctly works. However, after this simulation I have to analyse the data but matlab proceeds even if the simulation is not finished. I am thinking about using the COM-function IsSimulationRunning, which returns true if running and false if not, to say matlab to wait until this variable becomes false.
However I do not know how to do that. This because there should be a dynamic control of this variable to see if it is true or not.
How can I do that? Thanks

 Accepted Answer

Well, you can always write a while loop that test that the property is false.
%start simulation
while yourcomobject.IsSumlationRunning
%waiting for simulation to complete
end
%simulation is no longer running
%rest of the code.
However, if your com object triggers an event when the simulation completes, you may want to listen to that event instead. Details of the event would be required to explain how to do that.

28 Comments

Thank you for the answer. Now that you talk about the exact event it comes to my mind that it would be better to continue with the rest of the program once Plant Simulation has modified a .txt file (named OutData.txt) that will then be used in the rest of the program. This because I will do different simulations and each time Plant Simulation overwrite it.
Hope this event explanation is clear.
When I talk about events, I'm talking about COM events. That is something that would part of the interface of your COM object (maybe called SimulationCompleted). It's a bit like a function but it will specifically called event in the documentation of your COM object. It's easy in matlab to listen to COM event, hence my suggestion to use that if it's provided by your code object.
While it is possible to watch for file modifications in matlab (using .Net FileSystemWatcher), I found that in practice it's not very reliable. The problem is that you'll be notified as soon as the file starts to be modified, which is too early, not when the modification is complete (because that's actually impossible to detect).
I looked at the event of the COM interface but there only is the SimulationFinished event that I have to get informed if it comprehends all the functions that start with the end of the simulation or not.
Since the .txt that I am modifing is the last one and is really short (5 values), would it be possible to use this .Net FileSystemWatcher to detect the start of the modification, then putting a "timer" that waits for example 10 seconds, that is safely higher than the effective modifcation time, to start with the rest of the program? Does it make sense?
With the FileSystemWatcher you can either detect the change asynchronously by listening the to Changed event (that is your code will wait to be called until the event happens, in the meantime matlab can do other things) or synchronously using WaitForChanged (that is your code will wait for WaitForChanged event to return, in the meantime matlab can't do anything else).
The synchronous method is self contained:
%part common to both method:
watcher = system.IO.FileSystemWatcher;
watcher.Path = 'C:\somewhere\somefolder';
watcher.Filter = 'OutData.txt';
watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite;
%synchronous wait:
watcher.WaitForChanged(System.IO.WatcherChangeTypes.Changed);
%WaitForChanged returns as soon as a OutData.txt is written to
%... code that should execute once the file has been modified
In my case the synchronous method is the best one. I think thus that I will use that.
I was also thinking about modifying an empty .txt with Plant Simulation to use it as event starter. This because if I put this new .txt after those that I need, when the method notifies matlab it is getting modified the needed file by Matlab are ready and ths it can continue with the rest of the program.
However, now I am going to read the documentation and to test it. Thanks!
I am trying your code and Matlab doesn't give any error, however it is like if the change of the file isn't seen. Matlab just continue to not doing nothing even if the OutData.txt has been already modified. What the problem could be? I read through the documentation and it seems that the LastWrite change is continuously checked and thus I do not get where the problem could be.
Have you given it the right path?
To start with you could not set any NotifyFilter and pass System.IO.WatcherChangeTypes.All to WaitForChanged. This will definitively detect anything that happens to the file, creation, modification, deletion, file permission change, etc.
The code I've given works without any issue for me.
NF
NF on 27 Apr 2018
Edited: NF on 27 Apr 2018
I copied and pasetd the path and so it is correct, I checked for the differencies between the two codes using a comparator tool. I really do not understand why it stucks at the last command (WaitForChanged). I also tried to manually modify the file but it doesn't work either.
EDIT: I tried the code with simpler programs where I manually change the .txt and it perfecrtly works. Only in my program it doesn't work, even if I cahnge it manually. It really is strange that
What is the result of the following?
folder = ... %replace by actual folder of OutData.txt
watcher = System.IO.FileSystemWatcher;
watcher.Path = folder;
watcher.Filter = 'OutData.txt';
watcher.addlistener('Changed', @(~, ~) fprintf(2, 'Modification detected\n'));
csvwrite(fullfile(char(watcher.Path), char(watcher.Filter)), [1 2 3;4 5 6]);
watcher.EnableRaisingEvents = true; %from that point on the watcher will raise Changed event whenever the file is modified
csvwrite(fullfile(char(watcher.Path), char(watcher.Filter)), [7 8 9; 10 11 12]);
You should have one or more Modification detected printed in red at the command line.
NF's comment mistakenly posted as an Answer moved here:
I got some Modification detected with that. I think that the problem may be how Plant Simulation modify the .txt.
Looking more carefully in the documentation of Plant Simulation for COM interface I've seen that the SimulationFinished event comprehends also the modification of files done at the end of the simulation time because Plant SImulation stops the simulation an instant before the effective end to process the EndSimulation code. Thus, at the very end of the simulation the files have been modified.
Maybe it is possible then to use it for this issue, but I don't know how.
So with the exact same code, and with confirmation that when matlab modifies the file you get 'Modification detected' printed, can you confirm that you confirm you don't get the notification when the simulation modify the file? I find this hard to believe, we're hooking straight into windows here. I don't think there's a way to modify a file without the watcher noticing.
However, if you want to listen to the SimulationFinished event, that is very easy:
addlistener(yourcomobject, 'SimulationFinished', @SimulationFinishedHandler);
Then create the function SimulationFinishedHandler. If the SimulationFinished event follows standard windows convention, its signature should beL
function SimulationFinishedHandler(~, ~) %ignore the two inputs: source and eventargs
%do something when simulation is finished
%...
end
Thanks Guillaume. I do not understand what I should code now to make the program wait until the simulation is finished. Searching on the documentation I didn’t get if addlistener waits until the event is triggered. Then, in my situation what should I write in the function? The only thing that I want it is that once the simulation is finished, matlab continues with the rest of the program.
I’m not at home now and thus I cannot test with both the code and the confirmation code. I got an insight that Plant simulation when editing .txt blocks the write access to anything else. So, if WaitForChanged needs it, it cannot detect the change.
With the SimulationFinished event, you're now doing asynchronous programming. So, after you've issued addlistener, your code can do whatever it wants. If you've got nothing else to do while waiting for the simulation to finish then your code ends.
When the simulation finishes, the listener will be triggered and will call the SimulationFinishedHandler function. In that function (or a function you call from there) you now do whatever processing you need to do. There is no continues with the rest of the program in that the before and after the event are two completely separate functions. There are of course methods of passing data between the two functions if needs be.
Note: Not trying to confuse you any further, but depending on the desired lifetime of the listener, you may want to use event.listener instead of addlistener to create the listener.
Plant simulation when editing .txt blocks the write access to anything else That should have no effect on the FileSystemWatcher. It does not access the file in any way.
NF
NF on 30 Apr 2018
Edited: NF on 30 Apr 2018
I tried to implement the code and it returns me this error: Input needs to be a valid HG handle or a raw java object.
The only thing that I have to pass is the COM object because at the end of the SimulationFinishedHandler I have to use some command on it.
Regarding the event.listener, the lifetime is not dependant on my decision, it really depends on the specific simulation run and its number of data. I would say it may be between 30 seconds and 2-3 minutes.
I must say, I've never used COM events. I thought they used the same mechanism as matlab, java and .Net events, but no they've got their own. The following should work:
registerevent(yourcomobject, {'SimulationFinished', 'SimulationFinishedHandler'});
with
function SimulationFinishedHandler(varargin)
%varargin{1} is the COM object
%do processing
end
p.s. with regards to lifetime, it doesn't matter anymore because of the different mechanism for COM events, but this is not what I meant. With addlistener the listener stays alive as long as the object it is attached to exists, with event.listener it only stays alive as long as the object returned by event.listener is around.
I wrote the same code of yours and I get the error:
Error using comeventcallback (line 34)
Error firing event 'SimulationFinished' to 'SimulationFinishedHandler'.
Warning: Error occurred while evaluating listener callback.
I've searched a bit on the internet to understand what may cause this problem, but I couldn't solve it unluckly.
Good news, if you get this error that means matlab detected the SimulationFinished event. The error will occur if matlab can't find SimulationFinishedHandler.m or if the function is not defined with enough input arguments. If you used varargin as in my answer then this can't be the issue so are you sure that SimulationFinishedHandler.m is visible to matlab?
What happens if you do
SimulationFinishedHandler(1, 2, 3, 4, 5)
The error will also happen of course if any error happens inside simulationFinishedHandler.
The SimulationFinishedHandler.m file is in the same folder of the main program and thus it is visible.
The code I wrote is :
registerevent(PlantSimulation, {'SimulationFinished', 'SimulationFinishedHandler'});
and the function is:
function SimulationFinishedHandler(varagin)
% what to do
varagin.ResetSimulation('.Models.Frame.EventController');
varagin.SaveModel('C:\Users\***');
end
the (1,2,3,4,5) I supposed you meant to put it in the input arguments of the function like this:
function SimulationFinishedHandler(1,2,3,4,5)
Also in this situation I have the same error.
Yes, you'd get an error with that code. varargin is always a cell array. See this page for what varargin contains in this case. As I wrote varargin{1} is the com object (also in varargin{end-1}.Source):
function SimulationFinishedHandler(varagin)
simobject = varargin{1};
simobject.ResetSimulation(('.Models.Frame.EventController');
simobject.SaveModel('C:\Users\***');
end
Ok I didn't get that before. I corrected the code but still the problem occurs.
What if you don't have any code in the handler?
function SimulationFinishedHandler(varagin)
end
If you don't get an error with that, then the cause of the error is a bug inside your function.
If you do, then issue a
dbstop if caught error
before testing and give me the error that causes the execution to break into the debugger
I get the error also not having any code in the handler. With the dbstop the error given is:
Caught-error breakpoint was hit in winfun\private\comeventcallback at line 28. The error was:
Error using SimulationFinishedHandler
Too many input arguments.
28 feval(userMfileName, vals{2}, vals{3}, args, vals{1});
Oh! At some point in the thread, varargin (with two r) got changed to varagin (with one r). Change that varagin into varargin and all will be well.
And to get rid of the dbcaught if error, type
dbclear if error
Thanks! Now it works! I just have some problem with the COM interface commands now, but it is related to Plant Simulation. Thanks again!
Phew! Got there eventually
as said, the program now works. However it does only if I do one repetition. If I use a for cycle, it does only the first simulation and then it stops. My code is this one:
clc;
clear variables;
close all;
PlantSimulation = actxserver('Tecnomatix.PlantSimulation.RemoteControl.13.0');
PlantSimulation.LoadModel('C:\Users\***');
for ii=1:2 % 2 is just an example, It will be 40
PlantSimulation.ResetSimulation('.Models.Frame.EventController');
PlantSimulation.StartSimulation('.Models.Frame.EventController');
registerevent(PlantSimulation, {'SimulationFinished', 'SimulationFinishedHandler'});
end
As said, the first run goes properly, whereas the second one don't. I don't have any action with the COM object in the SimulationFinishedHandler and thus the Plant Simulation model is not closed. Is there maybe an issue with the registerevent (should I delete it each cycle?)? Is the for cycle skipped because of the registerevent?
What should I do to make the for cycle work?
Thanks again
There are several problems there:
  • registerevent should only be called once. What it does is tell the object PlantSimulation "Each time you trigger the event SimulationFinished, call my function SimulationFinishedHandler". It should be called before you start the first simulation otherwise you may miss the first event. The best place to register the event would be just after you created the object.
  • As I've said before this is all working asynchronously. The calling of SimulationFinished is completely independent of your main code. It happens whenever the COM object says it is finished regardless of what your main code is doing. Your main code may be even be finished. As a corrolary, your main code runs indenpently of SimulationFinishedHandler, it does not wait for it to execute.
Therefore, with your loop what happens is that you reset the simulation start the simulation, possibly too late register the event, then immediately move on to the next step of the loop independently of whether or not the simulation has finished, reset the simulation (which may still be running) and start a new simulation. Then needlessly re register the event.
If you want synchronous code, then we're back to my very first answer
PlantSimulation = actxserver('Tecnomatix.PlantSimulation.RemoteControl.13.0');
PlantSimulation.LoadModel('C:\Users\***');
for ii=1:2
PlantSimulation.ResetSimulation('.Models.Frame.EventController');
PlantSimulation.StartSimulation('.Models.Frame.EventController');
while PlantSimulation.IsRunning %wait for simulation to complete
end
%simulation is now finished
%do some processing
end %move on to the next simulation.
Ok, it works with the for cycle now. Thanks!!

Sign in to comment.

More Answers (1)

The accepted answer will cause your CPU to spin (wasting precious power and computational resources).
Instead, I found a "hack" that uses a built in function. Create a phony graphics element (e.g., with plot), tell matlab to waitfor it to be deleted and then delete it when you're ready to break out of the loop.
For example, this part of the code will wait for dsh to be deleted.
hold on;
dsh = plot(nan,nan);
hold off;
waitfor(dsh)
In your other code you can delete the dsh object to break out of the waitfor:
delete(dsh)

1 Comment

The accepted answer will cause your CPU to spin (wasting precious power and computational resources).
Notwithstanding the fact that your solution has nothing to do with COM and so is probably not applicable, if you read the whole discussion you'll see that I've extensively explained how to handle COM events asynchronously, which would not waste anything or wait for anything. However, the OP ended up wanting a synchronous handling.

Sign in to comment.

Tags

Asked:

NF
on 26 Apr 2018

Commented:

on 10 May 2019

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!