Example Code

Wait for Flag / Set Flag

Code and Documents

Attachment

Simple method of continuing execution, synchronizing processes, stopping loops, or anything else you might want to do by setting a flag.  Name multiple flags or leave unnamed for use on a single diagram.

Simple and full-featured examples included.

Framework Features:

1. Simplicity.  There are only 2 primitives ("Wait for Flag" and "Set Flag")!

2. Flags can be named, or in the simplest 1-local-flag-on-a-diagram case, left unnamed.

3. "Set Flag" is received by any number of "Wait for Flags"

4. "Set Flag" from anywhere within the application instance (even inside subVIs)

5. "Wait for Flag" from anywhere...

6. Dynamically choose to wait for new flag or include a previously set flag

7. Built in timeout can be used to throttle loops

8. Do not start section of code until ready (e.g. after initialization somewhere else)

9. Repeatedly execute a code section when trigger occurs

10. Start multiple, remote sections of code simultaneously

11. Supports reentrant callers

12. Timeout functionality is more flexible than dumb loop waits.  That is, if you are 2 seconds into a 10 second wait (e.g. record temperature every 10 seconds) when you "Set Flag", you don't have to wait the extra 8 seconds before exiting the loop.

13. No more creating terminals and local variables to stop parallel loops, setting panel controls to "Switch When Pressed", hiding panel objects, setting locals to false inside sequence outside the loop when all loops have finished to pop the panel object back since you just set it from Latch to Switch, etc.

14. No more global variables (VIGs, LV2s, FGVs, AEs, 1EQs, etc.) to create, maintain, and clog up your directories

15. No more wiring (and routing wires for) occurrence or notifier primitives for simple "Wait for" and "Go" operations.

Jason

Certified LabVIEW Architect

============

Version 3:

Added project library and uploaded VIP.

------------

Version 2:

-Bug fix:  "Set Flag" input was disconnected from the connector pane. (always took default value of TRUE)

-For perceived performance / real-time jitter improvements, switched to Variant Attributes for storing flag name/notifier pairs.

-Added "Remove After" input to both Set and Wait operations.  (Note that if you "Remove After" a Set and then call a Wait, the Wait will timeout.  To atomically remove flags where you set before wait, use the "Remove After" input on the Wait instead.  This input is also useful if you want to remove the flag upon Wait timeout.  The Set application is more obvious:  If you want to Wait in a loop with timeout and then later Set and remove the flag, use the "Remove After" input on Set.)

-Thanks to David_Staab for bug fix request and "Remove After" input idea.


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.

Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.

Comments
Baptiste_CA
Member
Member
on

Jason,

can you please tell us how you created the appearance of the your error clusters? You use the "modern" status control from the error cluster in the modern palette, and use system controls for code and source.

But I do not understand how you created/edited the appearance of the cluster container itself? It looks like a "system" control, but i did not find a system cluster container in the palettes...

LabBEAN
Active Participant
Active Participant
on

BaptisteCA,

The system error clusters are contained in the UI Control Suite: System Controls 2.0 package available through VI Package Manager and the LabVIEW Tools Network.


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Active Participant
Active Participant
on

Neat tool! I found this while looking for a workaround to some weird behaviors in LVRT with occurrences. While I don't think my problems are magically solved by changing to notifiers, I do like the API more. Here are some questions, ideas, 5 AM ramblings....

  1. Are you still using this? If so, have you tweaked it further but not published updates?
  2. I saw that the "Set Flag" control was disconnected, so I wired it up on my copy.
  3. I see that you're building an array in an FGV under the hood. That smells of potential execution jitter when using the API in several concurrent loops. I would expect the jitter to grow with the size of the array -- larger-dimensioned inputs to Build Array might require more memory management? -- so it seems prudent to keep the array small during execution. How about the ability to remove an individual flag after it's been set? The listeners already handle the resultant error, so it seems like a benign change.
LabBEAN
Active Participant
Active Participant
on

David,

Thanks for the feedback!  I haven't run metrics on Get Variant Attribute vs. Search 1-D array when the item doesn't exist yet.  It could make sense to switch to Set / Get Variant Attribute and to add support for removing an individual flag after it's been set by calling Delete Variant Attribute.  At that point, I'm not sure that I would even need the Set & Remove All input.  btw - I don't see the disconnected control you mentioned.

Yes, I still use this.  I shared it at the CLA Summit and one guy liked it and another said he just used Global Variables.  I'm happy to update it if you have other ideas.


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Active Participant
Active Participant
on

LabBEAN wrote:

I haven't run metrics on Get Variant Attribute vs. Search 1-D array when the item doesn't exist yet.  It could make sense to switch to Set / Get Variant Attribute and to add support for removing an individual flag after it's been set by calling Delete Variant Attribute.

Would you? Seems to me you could just provide a Boolean input for "Set and Remove Flag" and delete the notifier from your array when you retrieve it instead of just copying it. That would provide the Remove behavior for a single flag, and you could keep the Boolean for "Remove All", too.

I don't know that switching to variant attributes will buy you anything. Indeed, based on recent conversations I've seen here and on LAVA, testing shows that searching for a variant attribute is slower than searching for an item in an array lookup pair when the array is "small".

LabBEAN
Active Participant
Active Participant
on

I'm not sure how to benchmark "small" datasets, but between 1,000 and 10,000 items the atomic averages are fairly consistent in my own testing:

Average (Atomic):  Variant Attribute:  Set, Get, Delete = 2 us, 0.7 us, 0.7 us

Average (Atomic):  Array:  Add, Index, Delete = 0.9 us, 72 us, 12 us

I haven't seen the discussions you've read, but I'd be happy to post my code there so someone can check my evaluation.  If these results are relevant, the variant attribute primitives would be better suited for RT (speed and repeatability).


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Active Participant
Active Participant
on

LabBEAN wrote:


                       

I'm not sure how to benchmark "small" datasets, but between 1,000 and 10,000 items the atomic averages are fairly consistent in my own testing...

Who's creating 1000 flags in a single app?!

LabBEAN
Active Participant
Active Participant
on

As I said, I don't know how to time small sets (@ 100 operations that's 0.07 ms in this case).  Could you post some links where folks are sharing their results?


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Active Participant
Active Participant
on

On "continue_Set Flag.vi", did the connector terminals for "Set Flag (T)" and "Set & Remove All Flags (F)" get swapped in v2.0? After upgrading, every instance in my application had the wrong input wired.

Also, any chace of you putting this into a VI Package so I can wrap it into my project's "dependencies.vipc"?

LabBEAN
Active Participant
Active Participant
on

I may have added the Set Flag (T) input in a different location than you did when I fixed the aforementioned bug.  Here's a snapshot of the old / new context help windows:

continue_Execution v1 and v2 conpanes.png

After the long side by side (SxS) discussion, I've been hesitant to invest the effort to convert my tools to VIPs.  I like the idea of having versioned project libraries (LVLIB / LVLIBP, e.g. continue_Execution - 1.0.0.1.lvlib) to manange redistribution, but that sort of interferes with source code control (would require me to remember to create a new LVLIB version each time I touched a library member).  Would you really want this on your palette?


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Active Participant
Active Participant
on

LabBEAN wrote:

I may have added the Set Flag (T) input in a different location than you did when I fixed the aforementioned bug.

Ah, that makes sense!

Would you really want this on your palette?

Distributing a source code module as a VIP has nothing to do with putting its API on the LV palettes. I create and distribute all kinds of VIPs that are accessed directly from disk or through a project. I can see why you'd want to put the files on a palette for those who want to access them that way, but I don't see it as necessary since I access nearly everything through the LV Project and Quick Drop.

As for interfering with SCC, my versioning strategy is to keep a folder of dependencies (as installers, VIPs, or a single VIPC) in my repository and version it alongside the source code. If a dependency is updated in a release, the new dependency package is made available in that version of the repo. It keeps everything neatly accessible and in-sync.

LabBEAN
Active Participant
Active Participant
on

David_Staab wrote:

I create and distribute all kinds of VIPs that are accessed directly from disk...        

QuickDrop works if the VIs are just placed in vi.lib without adding them to the palette?  Good to know.  I think I'll include a palette item anyhow in the VIP for consistency.

David_Staab wrote:

As for interfering with SCC, my versioning strategy is to keep a folder of dependencies (as installers, VIPs, or a single VIPC) in my repository and version it alongside the source code.... It keeps everything neatly accessible and in-sync.
                   

You mentioned you're working with RT, so suppose you have a PC project and an RT project and the two code bases communicate.  While you would like to open up the source for both and run them together on your laptop for debug, if they use different versions of the same tool you're stuck.  This is because only 1 version of the VIP can be deployed to vi.lib at a time (correct?).  Aside:  When you install a VIPC, can you direct all package installations away from vi.lib and to a local project folder?

One idea is to not use VIPs and just use project libraries with version embedded in the library and containing folder names.  This allows multiple versions of the tool to exist SxS in vi.lib (if you like the VIPM scheme of keeping deployments in vi.lib) and also provides namespacing for loading multiple versions into memory within the same application instance.  However, this causes extra touch labor when using SCC because you have to do a file rename on the project library with each edition.

If files (VI, CTL, LVLIB) from VIPs can be directed to other places during install, there may be a hybrid solution here using VIPM and project libraries together to achieve SxS-disk and SxS-memory along with VIPM's capability to scan projects and build VIPCs.


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Active Participant
Active Participant
on

Some of these questions may need to be aimed at Michael_Aivaliotis, but I'll try to answer where I can:

LabBEAN wrote:

QuickDrop works if the VIs are just placed in vi.lib without adding them to the palette?  Good to know.  I think I'll include a palette item anyhow in the VIP for consistency.                 

It seems to find code placed anywhere the palettes would normally search. I know this includes <vi.lib>\addons.

You mentioned you're working with RT, so suppose you have a PC project and an RT project and the two code bases communicate.  While you would like to open up the source for both and run them together on your laptop for debug, if they use different versions of the same tool you're stuck.  This is because only 1 version of the VIP can be deployed to vi.lib at a time (correct?).  Aside:  When you install a VIPC, can you direct all package installations away from vi.lib and to a local project folder?                  

If they're using different versions of the same communications tool, I would expect some other stuff to go wrong, anyway. But yes, to my knowledge you can only have one version of a VIP installed on your system at any given time. I don't know of a way to redirect the installation paths that are baked into the VIP file.

One idea is to not use VIPs and just use project libraries with version embedded in the library and containing folder names.  This allows multiple versions of the tool to exist SxS in vi.lib (if you like the VIPM scheme of keeping deployments in vi.lib) and also provides namespacing for loading multiple versions into memory within the same application instance.  However, this causes extra touch labor when using SCC because you have to do a file rename on the project library with each edition.                  

I noticed that Project Libraries (.lvlib, .lvclass) deploy the entire library's contents if any one function is called, even if no others are. For large libraries, this can lead to substantial bloat, so I think twice before using them. (Yes, you can strip unused members in a binary build, but for debugging in the dev environment, you have to deploy the entire library.)

I also dislike that if one member of a class is edited, there's a chance that others will have to be recompiled with it. Sometimes members of other classes in the hierarchy are recompiled! I have no idea what the "rules" are for expecting that an edit will force recompilation in a seemingly unrelated file. Regardless, it can lead to SCC pains.

Appending a library's version to its name could be a VIPB Pre-Build Step. You'd never have to worry about it after setting it up the first time.

FWIW, I generally have a single repository for all projects in my "solution". If any project is using a component, all projects that want to use that component will have to upgrade to the same version. It hasn't been a problem in my short tenure as a project leader/developer, but I can imagine situations that might be strained by that constraint.

LabBEAN
Active Participant
Active Participant
on

Thanks for the input.

David_Staab wrote:

           

It seems to find code placed anywhere the palettes would normally search. I know this includes <vi.lib>\addons.        

Ran a test with a PPL deployed to vi.lib\addons and Quick Drop did not index the functions within.  Quick Drop did find the functions if the PPL was part of a project.  There appear to be IDE performance hits with PPLs, so I distributed Flags 2.0 with a standard LVLIB and added it to the palette.

David_Staab wrote:

           

If they're using different versions of the same communications tool, I would expect some other stuff to go wrong, anyway. But yes, to my knowledge you can only have one version of a VIP installed on your system at any given time.

You might find that Flags 2.0 has atrocious RT performance.  I guess at that point you could revert back to Flags 1.0 for both PC and RT but then you don't have the "Remove After" functionality you requested.  Hopefully, SxS will eventually be supported.  Until then, project libraries with some developer touch labor to place them can provide that ability when necessary.  Either way, I uploaded the VIP for completeness.

David_Staab wrote:                      

         

I noticed that Project Libraries (.lvlib, .lvclass) deploy the entire library's contents if any one function is called, even if no others are. For large libraries, this can lead to substantial bloat, so I think twice before using them. (Yes, you can strip unused members in a binary build, but for debugging in the dev environment, you have to deploy the entire library.)

I also dislike that if one member of a class is edited, there's a chance that others will have to be recompiled with it. Sometimes members of other classes in the hierarchy are recompiled! I have no idea what the "rules" are for expecting that an edit will force recompilation in a seemingly unrelated file. Regardless, it can lead to SCC pains.                   

I like having standard operating procedures.  So if tools can't be deployed SxS with VIPs, I'm not ready to make the jump quite yet even if they would work most of the time.  The trade-off as both of us have mentioned is working with the limitations of project libraries.

David_Staab wrote:


                       


Appending a library's version to its name could be a VIPB Pre-Build Step. You'd never have to worry about it after setting it up the first time.


                   

If we ever standardize on VIPM Pro and VIPC files I'll keep this in mind when deploying with VIPM to vi.lib.  For now, I (am / have gotten used to / sort of like) managing all required support libraries with the project dev code so that when someone pulls something out of SCC they have what they need.  This also solves the SxS issue for me in the short term.


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
gnilsson
Member
Member
on

I think a warning should apply to use this when starting vi's with Start Asynchronous Call Node. It's natural to use this aproch to stop such vi's.

The problem is that the vi that (indirectly) created the event, might finish execution before all asychronous vi's has stoped.

If so LabVIEW destroys the Notfier, and then the subvi('s) will create a new notifier(create if not found?), and this new one will probably never be sent.

LabBEAN
Active Participant
Active Participant
on

I place the following code at the far left of my top level VI.  Here, I create a flag named "Sub Loops" that is used to exit certain parallel loops later.  Calling the "continue_Wait for Flag" VI on the top level diagram before any other parallel VIs call it means that this VI and it's subVIs (e.g. "continue_Obtain Refnum" VI, which manages all references for the Flags framework) will not go idle until the top level VI goes idle.  Therefore, flag references do not go stale even if a parallel caller goes idle later as you described:

Create Flags at Beginning.png


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
Contributors