Jump to content
drjdpowell

[LVTN] Messenger Library

Recommended Posts

Hello, I have a little question about programming style.

What do you think of using typedefs for message data?

On the one hand when type changes in once place, all actors will get an update.
On the other hand it creates additional coupling between actors. I am not sure
what approach is better and why.

Thank you!

Share this post


Link to post
Share on other sites
On 1/30/2020 at 10:00 AM, Maksim Kuznetsov said:

What do you think of using typedefs for message data?

I don't tend to use them unless they have meaning beyond the message itself (ie. they are a natural grouping of data, rather than something that just exists for the message).  Most of my messages contain only one piece of data, so no typedef needed (unless that data is naturally a typedef).  Also, it is possible to go more than just a typedef: have an API of subVIs to send and receive the messages in a common library.  This can be a lot more powerful than just a typedef.  An example would be having any message starting with "Config:..." being passed to a Config subVI, with multiple possible messages being handled by that subVI ("Config: Get as JSON","Config: Set from JSON", etc.).  Another option is to send an Object that has multiple methods that the receiving actor can use.  I view a typedef as a poor cost-benefit trade-off, since you have the coupling issue without the maximum possible benefits.

  • Thanks 1

Share this post


Link to post
Share on other sites

Thank you once again Dr. Powell for sharing this powerful approach. I can see it being used in "Metronome" actor (e.g. Set Period).
And I already started to use it in my projects.

If you don't mind I would like to ask you another question: I have an actor (A) that launches a sub-actor (B) to delegate some tasks to it.
When sub-actor (B) publishes an event, actor (A) gets a message. However I would like to publish that message beyond actor (A). So that actors subscribed
to actor (A) would also receive events from sub-actor (B).

Currently my approach is to send Observer Registry of actor (A) to sub-actor (B) during initialisation. Then sub-actor (B) publishes its events into Observer Registry of actor (A) directly.
Another idea was to republish the event from actor (A) when it gets the message from sub-actor (B). Neither of these methods feel right to me. The first one shares internal reference
of the actor (A). The second method is not as efficient (receives, then sends again).

How would you approach this?

  • Like 1

Share this post


Link to post
Share on other sites

I have always done the second method, and just accepted the extra overhead of one extra message pass. Beware of premature optimization.  It is generally rare for me to want to just forward a message like this without the forwarding actor needing to change or react to the message in some way.

An alternate design is to accept that you don't have an actor-subactor relationship, but that your subactor should really be a helper loop of the actor.  A dedicated helper loop can share references no problem.  Your "actors sharing references" is a potentially suboptimal mix of "actors are highly independent but follow restrictive rules" and "helper loops have no restrictions but are completely coupled to their owner"

  • Thanks 1

Share this post


Link to post
Share on other sites

James,

Can you advise on the following build error using Messenger library please. My code is not broken. It runs from source perfectly fine.

image.png.d44ea41993a0063458cf4a2da424f540.png

Share this post


Link to post
Share on other sites
2 hours ago, Thoric said:

My code is not broken. It runs from source perfectly fine.

It's a common problem in LabVIEW.

Share this post


Link to post
Share on other sites
55 minutes ago, JKSH said:

It's a common problem in LabVIEW.

Thanks JKSH:

  • Closed LabVIEW and cleared the compile cache - same error
  • Altered the Build Spec to not "Remove unused polymorphic VI instances" - same error
  • Altered the Build Spec to not "Remove unused members of project libraries" - it built
  • Rechecked "Remove unused polymorphic VI instances" - it still built.

In Short: The key is disable "Remove unused members of project libraries". Can't recall having to do this before, but hey ho. Whatever works!

Share this post


Link to post
Share on other sites

Unfortunately, "Get Dynamic Launch Shell" gets a reference to a VI that calls the "Actor.vi" Dynamic-Dispatch method that is overridden by all your actors; i.e. practically ALL your application code!   It could have been anything breaking that rendered Get Dynamic Launch Shell" broken.  So it is near impossible to tell what was wrong.   If only that error message reported which subVI was the problem...

Share this post


Link to post
Share on other sites

Hello James,

There is a concept I am struggling to get my head around. For a long time I am following a method of not having typedefs in messages. Messages can contain various data and to make sure that the message is constructed correctly I have to consult the actor and copy the structure from it. Same applies for messages received. I believe this is called "zero-coupling".

1. If I am adding the actor reference to the VI, it brings all the dependencies of the actor to project, so I am becoming coupled to that actor, isn't it? (it is not like some generic reference)
2. Why in this case it is not advised to use actor's typedefs in messages (this could save time and less errors would appear during development)?
3. There is another method - to have a SubVI instead of typedef that will do the job of constructing (deconstructing) the message. But how is this different from using a typedef? SubVIs will also create more coupling.

I have a feeling that my understanding of coupling is not full. It would be great to hear your thoughts about these points.

Thank you! Kind regards,
Max

Share this post


Link to post
Share on other sites

There is no set way to do things.  Please use typedefs if you prefer.  There are many possibilities, and I am not necessarily using the best ones.

  • Thanks 1

Share this post


Link to post
Share on other sites

Thank you for your feedback. The honest reason why I am asking is a hope that someone will tell me which approach from many is the better one.
Every now and then I am having a dispute over this with my colleagues and I am always saying that typedefs create additional coupling, but I realised that I never
understood what it actually means, it was like a rule I used throughout my projects. Now I am not sure if I was right or wrong, clearly I have a lack of knowledge.

Maybe someone can share their approach and reasons behind it? Thank you!

Share this post


Link to post
Share on other sites
On 4/20/2020 at 7:59 PM, drjdpowell said:

Unfortunately, "Get Dynamic Launch Shell" gets a reference to a VI that calls the "Actor.vi" Dynamic-Dispatch method that is overridden by all your actors; i.e. practically ALL your application code!   It could have been anything breaking that rendered Get Dynamic Launch Shell" broken.  So it is near impossible to tell what was wrong.   If only that error message reported which subVI was the problem...

I wanted to get back to this thread because you've effectively said that by using dynamic-despatch the actor launcher is pulling in virtually all my code and therefore it is near impossible to tell what's wrong; implying that there is a broken VI somewhere in my code that prevents the app builder from completing. But I'm certain there isn't anything broken. The code runs in the IDE. If I open all VIs there are none broken. None. So I don't see how your argument stands. I need to discuss further because I'm encountering annoyances associated with the workaround to disable "Remove unused members of project libraries" option and would like to go back to getting this properly sorted.

Share this post


Link to post
Share on other sites

Have you tried building your actors individually into EXEs?  To see which one breaks.  Make a new build and make the top level vi only one of your actors and see if it builds.  Then swap in a different actor.  Hopefully, they will all build but one, which narrows down where the problem is.

Share this post


Link to post
Share on other sites
3 hours ago, drjdpowell said:

Have you tried building your actors individually into EXEs?  To see which one breaks.  Make a new build and make the top level vi only one of your actors and see if it builds.  Then swap in a different actor.  Hopefully, they will all build but one, which narrows down where the problem is.

OK, good idea. So I painstakingly built each actor independently and 11 built fine, 10 failed. I think some of those that failed are only failing because they call one of the other failing child actors, so of the 10 failures only 5 are at the bottom of the tree hierarchy and I think these are the culprits.

So now, the question is "What about these 5 failing actors is causing a build failure?". Do they exclusively have something in common?

Their roles are:

  1. One is Dialogue style GUI Editor for populating an Array - a relatively simple actor.
  2. Another is a Dialogue style GUI Editor for a more complex file management need. Manages remotely (FTP) stored files.
  3. A third Dialogue style GUI Editor for managing another Array - a relatively simple actor, like (1).
  4. A local file management actor for receiving configurations and collating them into a JSON file - a simple decoupled actor with the ability to gather JSON objects from any other actor for storage and retrieval.
  5. A simple actor that adds log entries to a local text file, and uploads the local file to a remote FTP folder.

So they don't all have one common dependency that the other actors don't also use. The first three present their FPs, but so do many other actors. Some depend on FTP interaction, using a separate internal library we have, but not exclusively so.

I think I'll try cloning one of these 5 actors, trial build it then strip out 1 feature, and repeat until it builds successfully to determine which component is the problem...

Share this post


Link to post
Share on other sites
1 hour ago, Thoric said:

Their roles are:

  1. One is Dialogue style GUI Editor for populating an Array - a relatively simple actor.
  2. Another is a Dialogue style GUI Editor for a more complex file management need. Manages remotely (FTP) stored files.
  3. A third Dialogue style GUI Editor for managing another Array - a relatively simple actor, like (1).
  4. A local file management actor for receiving configurations and collating them into a JSON file - a simple decoupled actor with the ability to gather JSON objects from any other actor for storage and retrieval.
  5. A simple actor that adds log entries to a local text file, and uploads the local file to a remote FTP folder.

So they don't all have one common dependency that the other actors don't also use. The first three present their FPs, but so do many other actors. Some depend on FTP interaction, using a separate internal library we have, but not exclusively so.

I think I'll try cloning one of these 5 actors, trial build it then strip out 1 feature, and repeat until it builds successfully to determine which component is the problem...

This is a long shot here, but do they all need to run in the UI thread but their preferred execution system is set to "same as caller" and then something gets screwed up when they are called by dynamic dispatch in the runtime?  What happens if you set their preferred execution system to "user interface" and retry.

 

Share this post


Link to post
Share on other sites

@Thoric

I have seen similar behaviour before. There are two scenarios I have seen.

1. It turned out that some code I had naughtily left in a diagram disable structure was "out of date". If I recall it was a class method that was broken or perhaps the class had "stale" data in its history. Resetting the class mutation history sometimes fixed this.

2. Are you sure you don't have any broken methods (like perhaps a test or prototype VI in a class somewhere that you never got around to updating) in the project? This kind of error is hard to track down as everything will run fine in LabVIEW.

It might be quicker to roll back to when it last worked and then look at your next commit to see what changed.

Edited by Neil Pate

Share this post


Link to post
Share on other sites

So I started by cloning the first actor that has a problem and creating a build spec for it, then removing content bit by bit until it built OK. It was only happy when I removed the last reference to a typedef cluster that belongs to another library (which I'll call LibraryA).

I started again with the same actor, cloned it, checked it still doesn't build, removed only references to LibraryA's typedef by "disconnecting from typedef" wherever it appears in the actor and it then built ok straight away. The fix has nothing to do with all the other things I'd removed, just typedef linkages to other libraries.

I tried the same with the second failing actor. Check it still fails to build. This actor has typedefs from two other libraries in it (LibraryA and LibraryB). Removing links to these wasn't enough. I also had to remove links to all typedefs, including one that belonged to a toolkit. Then it finally built.

Thoughts anybody? Every actor I've created has typedefs from libraries and toolkits in it. But only these five actors appear to have a problem with incoroprating them. 

@Neil PateThanks for the idea, but these actors have no stale or unforgotten disabled code in them. They're really clean and some a even super simple. The classes also have no bad VIs in them.

@bbeanThanks for the idea, but I haven't changed their thread preferences. I'm not sure actually can without breaking the dynamic dispatch rules.

Edited by Thoric

Share this post


Link to post
Share on other sites
8 hours ago, Thoric said:

Thoughts anybody? Every actor I've created has typedefs from libraries and toolkits in it. But only these five actors appear to have a problem with incoroprating them. 

My gut feeling says that a Mass Compile could make this problem go away.

Share this post


Link to post
Share on other sites

Question: if you take an actor that has the problem, and remove it from its class (making it an ordinary non-dd vi) does it still not build?  I want to know if this is a problem that requires DD and your library typedefs together, or just the typedefs.

Edited by drjdpowell

Share this post


Link to post
Share on other sites
15 minutes ago, drjdpowell said:

Question: if you take an actor that has the problem, and remove it from its class (making it an ordinary non-dd vi) does it still not build?  I want to know if this is a problem that requires DD and your library typedefs together, or just the typedefs.

OK, so I made a Source Distribution out of the failing actor, which included all it's references/dependencies. Wrapped this one actor and the copied dependencies into a new project, created a build spec and it fails. Good. So I have a test environment. Checked into SCC.

Remove ActorNR.vi from Class
I removed ActorNR.vi from the class (with the rest of the class content to maintain accessibility) changed the DD terminal to Optional. It still fails. If I run ActorNR.vi it works fine. So this problem isn't necessarily related to the DD requirement.

Mass Compile
I don't think this is necessary given I've created a fresh Source Distribution, but tried for completeness. No reported errors. The build still fails.

Note: The build error (Cannot save a bad VI without its block diagram) appear to suggest the problem is with: vi.lib\drjdpowell\Messenging\Parallel Process\Parallel Process Library\Startup Handshaking.vi. Clearly this VI is not broken in source.

Remove Identity from ActorNR.vi
I realised the ActorNR.vi was still referencing actortype2 as it had the identity class control. Deleted it. Build still fails, same error but now it points to vi.lib\drjdpowell\Messenging\Parallel Process\Parallel Process Library\Startup type 2.vi

Investigating the dependency libraries
One of the three libraries this actor calls upon actually contains a Messenger actor. An actor that's not required in this case, but exists within that library. When removed from the library, the build process succeeds.

Rewind
I rewound my source code branch, so this problematic actor is now an actor again, and tried the last step of removing the other unused actor from the dependency library. Build succeeds.

So this is my situation (see image attached).
 

 

buildfail1.png

Share this post


Link to post
Share on other sites

My fix for now is to move the "IGOR_Sync.lvclass" actor out of the containing library "IGOR Sync.lvlib". This ensures the actor isn't present and therefore not "removed as an unused item from the library" during build.

But I think I need to get to the bottom of why this perfectly valid situation is creating a build failure. Any thoughts? Is the class structure/tree being broken in the builder when the unneeded actor is removed from the library? That would be a LabVIEW builder bug.

Share this post


Link to post
Share on other sites

I've narrowed this down to this probable cause:

If an actor in a library that's drawn in as an unneeded dependency uses "TCP Actor" to make it remotely accessible then the build of the structure fails when "Remove unused elements from Libraries" is set in the app builder, as is the default for LabVIEW.

I've attached code that demonstrates the build error (LV2017) and if you remove the TCP Service subVI from the actor UnusedClassWithinLibrary.lvclass the build then succeeds.

@drjdpowell Any clues as to why using the TCP service features on an unused actor within a library could cause a build to fail?

Needing to keep "Remove unused elements from libraries" set in the builder inflates my executable by over 100% because it then draws in masses of unnecessary code.

messengeractortcpcreateserroronbuild.png

MessengerActorBuildFailDemo.7z

Share this post


Link to post
Share on other sites

I'm guessing this is an edge-case builder bug.  I realize, though, why I have not seen it; I am hesitant to use LabVIEW Libraries.  I don't put typedefs in libraries at all if they are going to be used by a component independently of the other stuff in the library, and I rarely if ever put a Class inside a Library.   Libraries should be a good thing, but the "load everything in the dev environment" is a real negative.  Here, the bug you are suffering is in the builder code to strip out the useless connection to the unused library elements.   That builder code shouldn't even need to exist, as there is no reason to load code that is not used.  

The fact that your IGOR Library has "Utilities" and "Common Typedefs" tells me you are using LabVIEW Libraries the way they SHOULD work: convenient collections of things that you might use some of.  But Libraries are too flawed to be used as they intuitively should be.  Hopefully, they will address this in NXG.

Share this post


Link to post
Share on other sites

I'll have a look at your Demo when I get the chance, to see if I can find a work around (other than not putting actors in Libraries).  Unfortunately, "Messenger  Library" is built on the principle of doing asynchronous things without being blocked by "Root Loop" (a little known but critical flaw of async calls in LabVIEW), and that restricts how I "launch" actors.  The NI "Actor Framework" uses the same/similar method; I wonder if it has a similar problem.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Similar Content

    • By drjdpowell
      An extensive library for passing messages between parallel processes. Generalizes the communication method, allowing the message sender to use the method provided by the receiver. Supported communication methods include wrappings of simple queues, user events, and notifiers, as well a more complex channels such as a TCP server and client. In addition, one can configure simple forwarding addresses (“Observers"), which can send messages to multiple destinations, optionally with modifications such as adding a prefix to the message label, relabelling, or substituting a different message.
      Communication patterns supported include request-reply (asynchronous or synchronous), where the reply is sent to a "reply address" attached to the request, and register-notify, where one process sends a registration message to another in order to subscribe to a series of updates.  Also supports scatter-gather, the gathering of replies from multiple senders into an array of messages.
      An option framework for dynamically-launched VI "actors" is also provided, including example templates, which can be accessed via the Tools menu (from an open Project, select Tools>>Messenger Library>>Create Actor from Template..).  An "Actor Manager" debug tool is also installed under the Tools menu.  Please note that this package has nothing directly to do with the NI Actor Framework (other than both packages are influenced by the Actor Model).
      ***Introductory Videos are on a YouTube channel.***
      ***A great summary of many Messenger Library sources, provided by Bob W Edwards***
      Original conversation on this work is here.

      Now hosted on the LabVIEW Tools Network (but note that the latest version will often be on LAVA)
      ***NOTE: latest versions require VIPM 2017 or later to install.***
    • By drjdpowell
      I've started to make some instructional videos on YouTube for my Messenger Library.   I was inspired by Delacor's nice videos on their new DQMH framework and also by Steve Watts' CSLUG channel.  Any feedback appreciated.
       
      James
    • By drjdpowell
      I’m hoping to add some sample projects to my “Messenging” package, and I thought it would be easy and instructive to rework one of NI’s templates, “Continuous Measurement and Logging”, as it is already somewhat actor-like with three communicating modules.  Attached is a (back-saved for 2011) copy of the NI project, with my version included (run “Main.vi” for the original, “Main.lvclass:Actor.vi” for my version). 
       
       I kept the basic functionality the same, but couldn’t resist changing some of the UI (in the old code, “Main” controls the UI; in the new code, published state messages from the Acquisition and Logging Actors set the UI).
       
      Continuous Measurment and Logging with Messenging.zip

       
       Any comments appreciated.   Is this example less clear than the NI original?  Why?  How could I improve it?
       
      In particular, is code like this (the most complicated interaction, I think) understandable without heavy documentation?  It’s a “Start Logger, then Start Acquisition, then Unset the Busy Cursor” three-actor chain message:

      I’m thinking of making a “Send Chain Message” subVI (that accepts arrays of addresses and message labels) to replace the above code.
       
      — James
    • By torekp
      At http://zone.ni.com/d...a/epd/p/id/4394, NI provides some example code for using Windows Messaging in Labview 2009. But the example generates and intercepts the messages in the same single toplevel VI. Is it possible to converse between two VIs using Windows Messaging? Would I need (or be able) to create a new DLL in order to do that?
      Toplevel:

      Create Windows Message Queue:

      From the Readme file:
      **How it works**
      A DLL included does all of the dirty work. The VIs in the library are primarily
      wrappers around the DLL with the exception of Wait for Windows Message.vi.
      When creating the first Windows message queue, the DLL installs a windows Get Message Hook and a CallMsgProc Hook on the LabVIEW process. This allows the DLL to inspect all messages heading for LabVIEW before LabVIEW processes them. The hook function determines whether each individual message is a message in which the queue is interested. If it is, it adds the message to the queue, and sets an occurrence. The Wait on Windows Message.vi is waiting on the same occurrence, and thus it continues its execution, retrieving the message from the queue. A number of utility functions are also provided for working with the queue.
      --------
      Any advice appreciated, even if it's "abandon all hope". (I'm a very weak C programmer.) I'm attaching the CPP code for the DLL, as a text file.
      Windows Messages for LabVIEW.txt
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.