01-19-2024 02:51 AM
Hi,
this subject has been discussed many times, but I have not found really relevant info for anything more complex than a project vi only couple VIs.
Our project has about 20 modules running in parallel. Theoretically speaking each one of them should be able to stop all the rest in a controlled manner, but in reality the ability to stop the app is restricted to couple modules. Each module has several subVIs inside as expected. So of these subVI should constantly do things others really has to take action based on events.
The first iteration of our "AppStop" VI (AS) was a latching FGV. I had a "Stop App?" input and a "Stop App!" output. If anybody sets the input to true from that point the true value is latched and everybody else everywhere will know that its time to stop. Now the problem with this, is that we have VIs really should sit idle in 99.9% of the time but to realize that it should stop it needs to poll the AS vi periodically. This - in my opinion - messes up the VI as however its functionality doesnt require constantly doing something, I have to apply some sort of a continous reading of the FGV. It also makes debugging harder cause now the VI is contionusly doing something while just by its function it could stay rest.
To mitigate the problem I thought that I will make the AS event based, so whenever the Stop App? set to true it generates an event. The subVIs register to this event and act accordingly. This works very well in simple VIs which practically has only an event structure, but for more complex VIs its possible that we lose the event as it might be generated when the execution is in between two event structure (one of them is not processing it anymore the other one is not registered to it yet).
So I have ended up using both the method, some VIs stop based on the latched output, some stop based on the event. But it stinks to me, and I believe there should be a cleaner way to solve this.
Let me know your thoughts.
01-19-2024 04:10 AM
To Stop multiple VIs or Loops , I Prepare to use Notifier with Enum/Boolean, Where I will be reading the notifier status continuously in the Loop and whenever it notifies as exit I will be exiting the Loop or the Module.
I have 10+ Loops Running in parallel and I could Stop instantly.
01-19-2024 05:25 AM
As far as I understand this is pretty much the same contionusly reading a latching FGV, exactly what I try to avoid.
01-19-2024 06:50 AM - edited 01-19-2024 06:51 AM
@1984 wrote:
As far as I understand this is pretty much the same contionusly reading a latching FGV, exactly what I try to avoid.
well there's this
https://knowledge.ni.com/KnowledgeArticleDetails?id=kA03q000000YI57CAG&l=en-US
I assume, "Abort VI" in the above picture is like pushing the red stop button , or using https://www.ni.com/docs/en-US/bundle/labview-api-ref/page/functions/stop.html
01-19-2024 08:02 AM
Using the stop function or aborting the VI is the exact opposite of stopping a VI in a controlled manner, so these two can not be used and generally should be avoided.
01-19-2024 08:50 AM
Don't unregister/reregister the event between event structures. Use the same registration for both event structures.
Register the event when the VI starts; unregister it when the VI exits.
01-19-2024 09:22 AM
I am a fan of the Channeled Message Handler. In my case I have several loops running in parallel.
Each loop is basically a State Machine so every loop has an "Exit" state.
The main control loop sends an "Exit command" to all the other loops, waits for an ACK that each loop has stopped and then stops itself and the program exits completely.
01-24-2024 04:16 AM
@paul_a_cardinale wrote:
Don't unregister/reregister the event between event structures. Use the same registration for both event structures.
Register the event when the VI starts; unregister it when the VI exits.
If I understood this right then I dont think it helps. Lets say one of my modules have a loop which has three VIs connected in series. All of them are doing their job until they finished with it OR if an AppStop occured somewhere else. That "somewhere else" VI generates an AppStop event and lets say that event is captured by the first VI in the series so it stops. But as the event is processed in one of the event structures it wont trigger an even in the second VI.
It is possible and I considered that if an event structure captures an AppStop event than it immediately triggers another event. By this I can guarantee that every event registered to the AppStop event will stop, but at the same time it forces the programmer to not forget putting a new event generation in every AppStop case which is a pretty inconvenient and error prone coding standard.
Another option is creating a module which starts at the very beginning of the application and registers to the AppStop. Once it got the event it starts flooding out AppStop events lets say in every 10ms all the way until at the very end of the main application (when we know that everybody has stopped) we can stop this module. This could work and doesnt give the programmer too much extra work but it doesn't look very elegant.
01-24-2024 06:18 AM
@1984 wrote:If I understood this right then I dont think it helps. Lets say one of my modules have a loop which has three VIs connected in series. All of them are doing their job until they finished with it OR if an AppStop occured somewhere else. That "somewhere else" VI generates an AppStop event and lets say that event is captured by the first VI in the series so it stops. But as the event is processed in one of the event structures it wont trigger an even in the second VI.
It is possible and I considered that if an event structure captures an AppStop event than it immediately triggers another event. By this I can guarantee that every event registered to the AppStop event will stop, but at the same time it forces the programmer to not forget putting a new event generation in every AppStop case which is a pretty inconvenient and error prone coding standard.
Another option is creating a module which starts at the very beginning of the application and registers to the AppStop. Once it got the event it starts flooding out AppStop events lets say in every 10ms all the way until at the very end of the main application (when we know that everybody has stopped) we can stop this module. This could work and doesnt give the programmer too much extra work but it doesn't look very elegant.
You certainly shouldn't need to send multiple AppStop, then you have some bad design. If VIs are serial it's easy enough to send out a Stopped boolean or simply set an error "User stopped" that'll prevent the following VIs to run.
As for parallell tasks, a Notifier or Event solves it well.
01-24-2024 06:55 AM - edited 01-24-2024 07:01 AM
You certainly shouldn't need to send multiple AppStop, then you have some bad design. If VIs are serial it's easy enough to send out a Stopped boolean or simply set an error "User stopped" that'll prevent the following VIs to run.
As for parallell tasks, a Notifier or Event solves it well.
As I wrote above my VIs use event structures. If during the execution of VI#1 the event occurs it stops VI#1, but then VI#2 again registers the event (or I roll the dynamic event terminal from VI to VI) as the event is alreay fired it just stay there.
I could query the notifier status periodically but right in the original post I mentioned that I'd like to avoid continously polling something in the timeout of the event structure. As this would be a very simple latching notifier I wouldn't even bother using it cause I could use a latching FGV.
Stop boolean? Sure it might work if you have four VIs, not when you have hundreds. Plus of course does not work with events.
An error could be used, thats true. Its not the holy grail thoughas at a certain point I need to differentiate between "non-critical" and "app stop" type errors which again introduces a new coding "must do".