11-01-2024 09:19 AM
Clonable modules in DQMH are set to shared reentrancy, not preallocated. If you stop/destroy a module, but then create a new clone it might just fire up a previously active clone.
If this module calls VIs that are set to run with preallocated reentrancy and these have feedback nodes that need to initialize on load or first call the clone will not reinitialize those feedback nodes this time because the VIs were preallocated (and used/set their first call / load flag) when the shared caller was originally created, not when this new module was started...(or rather re-started due to its shared reentrancy).
This means that you have to make sure every module clone forces a reinitialization of such feedback nodes in the VIs it calls by other means (instead of relying on the clone and its subVIs to be unique copies with no prior state....). Or have I overlooked something (I have not spent much time on the issue yet as it just bit me at a very inconventient time... :-O)?
If correct, this can be quite tricky to get around/require a lot of extra code (although that is what I have done just now; moving feedback nodes out of the preallocated reentrant subVIs and moving the initialization to the out loop to be able to reinit on next launch of the module). Can clonable modules be set to be preallocated instead to overcome this (just setting a module from shared to preallocated does not do the trick though it seems), or how do you deal with it?
11-01-2024 06:15 PM - edited 11-01-2024 06:15 PM
> Or have I overlooked something
The preallocated setting only applies to static subVI calls. This means that static subVI nodes dropped on the block diagrams of non-dynamically-launched VIs will be guaranteed to have their own, non-shared data spaces if the subVI is marked as preallocated reentrant.
Since cloneable modules are launched dynamically, the preallocated setting has no effect. This is true for DQMH cloneables, AF Actors, and any other entities in frameworks that support dynamically launched reentrant instances.
Put more simply, you'll see the exact same behavior you're describing with DQMH cloneable modules, regardless of whether they're marked as shared clone or preallocated clone.
I have occasionally run into the exact scenario you describe, and my solution is to ensure that cloneable modules always set any state to known values somewhere in the "Initialize" frame of the MHL. Which in my opinion is a best practice for any dynamically-launched code.
11-02-2024 06:06 AM - edited 11-04-2024 03:52 AM
In the old days when reentrant VIs were more limited we cloned (dynamically launched a copy) by opening a reference to a template or physically copying the VI on disk and running it..So it was really a unique VI which really allocated new static (the preallocated reentrant ones) VIs to call (still useful today, for easier debugging e.g.)..
This is the behaviour I wanted and have (somewhat incorrectly then) mentally modelled with the preallocated reentrancy set on the dynamically called clones, but in reality it is not about that settings, but whether there is an Open VI reference triggered, an actual fresh copy is forced/allowed to be created or not...Which it is not in this case (DQMH framework etc); It only opens a VI reference to the clone when the first clone is made, after that it reuses that "master reference". One reason for this I guess is that later cloning does not risk being blocked due to root loop access. In my case the application is headless (runs as a service) so root loop blocking due to GUI-actions is less of a worry..
Having an option in DQMH to open new references when cloning instead of reusing the old "master reference" could be a solution. It would have to come with a warning that if this option is chosen cloning could be blocked by the root loop, but the advantage would be that each module and its static preallocated reentrant VIs would launch fresh.
11-04-2024 01:14 PM
The DQMH designers opted for the 0xC0 option on Open VI Reference, which allows for multiple 'fire and forget' reentrant clones that can run independently when launched via Start Asynchronous Call. With this option there is no way to force new clones to be instantiated. In other words, the clone pool is *always* used. Note that this is the same approach taken by Actor Framework and multiple other LabVIEW frameworks, as it allows for the most flexibility and performance.
There is an option when launching a cloneable module to close the master reference:
The default for this is FALSE. Here is the text from the comment on the diagram of Init Module.vi explaining the purpose of this setting:
"The Close Master Reference parameter specifies whether or not the Master Reference used for launching clones will be closed when the module is shutting down.
If FALSE (default): The master reference will remain open even when the last clone shuts down. A future Start Module call will continue incrementing module ID values after the last one that was created. Your code will *not* be susceptible to root loop issues since Open VI Reference will only be called a single time, no matter how many times all the cloneable modules are stopped while Start Module.vi is running or reserved for running. You may see odd behavior if you are changing the 'run as singleton' value between Start Module calls.
If TRUE: The master reference will be closed. A future Start Module call will restart module IDs at 1. However, your code will be susceptible to root loop issues since Open VI Reference will be called any time you start a clone and the master reference was previously closed."
So it sounds like you would want this option to be TRUE, but even then, the closing of the master reference only happens when all instances of a cloneable module have been stopped. What you're asking for is a different launching mechanism, where a new master reference is always used. That would require changing the behavior of the framework in Start Module.vi, which is probably possible, but again, in my opinion, the better approach would be to initialize any state data in the 'Initialize' frame of your Main VI MHL.
05-06-2025 04:28 AM
The issue with having to initialize all state data instead of "getting it for free" by not reusing previously used clones is that it easily becomes *a lot* of it: Hey, the user moved a splitter bar the last time that clone was opened...I'll have to move that back now e.g. Some of the state information may also not be as readily available and/or practical to define in a programmatically readable way.
Just to give another example in addition to the splitter bar already mentioned: the default window size (not minimum e.g., which I can read, but do not want to match the default..): Someone had a clone opened and maximized its window, then closed it:
The next time a clone is created I want that window to open in its carefully chosen default size, but that information is not easily obtainable for the VI during its initialization state if I want the actual default it was saved in to dictate it (which is practical as what you see is then what you get...).
I'll have to get a reference to the original and check what its pane size etc, is if I want what I designed graphically to decide how a newly opened clone should look like.
You might say that instead of doing a reinitialize all controls to default, what I really miss when clones are reused like this is a "Reinitialize front panel layout to original"...
05-06-2025 10:12 PM
Sounds like you need either a configuration editor that remembers such things and initializes them in the initial case (check out DCFG, which is free for DQMH enthusiasts)…
or, you could create a brat VI that you can drop in the block diagram of your clone, gets its VI reference and goes to town setting up everything you the way you want it
05-07-2025 04:03 AM - edited 05-07-2025 04:16 AM
What I *want* is for the design of the initial state of the VI GUI to automatically define how any clone (re)started will look instead of having to duplicate that into a configuration file and initialization logic.
But yes, what I need (and have), when clones are reused and keep their previous state, is to (continue to) duplicate this into a configuration and reinitalization logic.
For GUI states this requirement could have been avoided even for shared clones though if there was something like the "Reinitalize to Default Value". It would set the visibility, position, color, size etc of all GUI items (window, splitters, panes, controls, indicator etc) to their original state (as saved in the original). When a fresh clone is created you get this for free; the design you define din the original is applied with no extra configuration or logic required. Being able to do the same for reused clones, when those are preferred or cannot be avoided, would be nice.