Jump to content

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!

Link to post
Share on other sites
  • Replies 284
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Writing the notes forced me to watch the videos closely. I'm going to use the notes as a quick-ref whilst getting started and hoped others might have a go if they had them too. Feel free to make chang

For anyone using this package, I’ve uploaded the latest version (should really have updated this more than once a year).  I’d like comment on the following new features: This is one of three asynch

Here is an illustration of what Thoric is discussing.  Calling code starts two actors: an “Instrument" actor that is publishing a “Readingâ€, and a “Furnace†actor that expects to receive “Fu

Posted Images

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
Link to post
Share on other sites
  • 3 weeks later...

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
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
Link to post
Share on other sites
  • 1 month later...

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

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.

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!

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...

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

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
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!

Link to post
Share on other sites
  • 2 weeks later...
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.

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.

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...

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.

 

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
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
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.

Link to post
Share on other sites
Posted (edited)

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
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

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.

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

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.

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.

Link to post
Share on other sites
  • 2 months later...

Hello everybody,

I am currently cleaning up my projects and thought of the way that could potentially reduce the amount of things loaded in the development environment.

This is the architecture used at the moment:
Actor named "Main" launches actors A, B, C, D, E. The last actor E is launched and requires addresses of C, D.
I pass these addresses (C, D) as specific actor references.

That means that if I want to debug just actor E, the development environment will load actors C, D as well.
And if one of them is broken, actor E will appear broken as well (even if I don't want to test functions related to C, D).

Idea:
Instead of passing specific actor references to actor E,  I can use generic references for C, D (Actor type 2\Actor type2.lvclass) in actor E.
Then if I want to work on actor E, actors C, D won't be loaded.
_______________________________________________________________

Before implementing this idea for my project which will take substantial time, I would like to hear your opinion on this.
Maybe I am missing something. Thank you in advance!

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***
      JDP Science Tools group on NI.com.
      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
    • By jbjorlie
      I am working on a complete redesign of our instrument control software. I'll be using LVOOP and some form of messaging/queue system. The program must control 10+ different types of instruments, each having variations in I/O (pressure control, temp control, motors, different types of controllers, etc...). Most of our instruments run from a touchscreen attached to an embedded PC. A few run from a desktop and we have some that need the desktop version to control multiple instruments at the same time (using a tab control in my old program).
      So far I have a top-level vi that decides if this is a touchscreen, desktop, or simple test-viewer and launches the proper set of user interfaces. There are UI's for IDLE state, Test Setup, Config, Calibrate, Run Test, and so on... I have been studying discussions here from the super-megadudes on frameworks, lvoop, messaging, and how NOT to do things. After giving my best shot to AQ's AF I'm now using LapDog messaging from Daklu & it is time to ask some questions!
      1. Would you recommend using a single top-level UI and then plugging in different pages (Test Setup, Idle, Run Test, etc...) via sub-panels? In the past I have found that complex sup-panels can really slow things down. However, without them I end up seeing the desktop when switching between UI's. Not a big deal but not very professional looking.
      2. On the framework subject, is it better to have my I/O channels messaging a mediator who then messages the current UI or should they message the UI directly?
      3. What about updating indicators? It seems that passing UI indicator references to CHx is faster than CHx sending messages to the UI (or to mediator then to UI). I need good response time: Example - I want an LED to light up on the front panel when a heating relay is turned on and off. The relay may only be on for 50ms every second. Can I really send a LED ON msg and then an LED OFF msg and expect it to work smoothly? For 2-8 channels at once?
      3. Should I be re-opening the channels every time I switch UI pages or should I initialize them once and leave them running even when they are not doing anything? If the latter, what happens to the queues when the UI closes and another opens? I could pass the callee queue but what about the caller queue?
      4. I have a CHx parent class with children for each I/O "type". At runtime, some stored config information would tell CHx what child to use, which channel # this is, what to label the UI controls and indicators, and, according to the type of UI (also using classes), which controls to show/hide for appropriate functionality. There was a thought of giving each I/O class a UI and then plugging them into sub-panels on the bigger UI but I thought that may be too confusing for the poor sucker that inherits my code. It already seems that using LVOOP and a messaging framework distorts what I think of as "dataflow" drastically. Any quick thoughts on this or pointers to similar discussions?
      Here are some UI screenshots so you can get an idea of what I am doing:

      I truly attempted using the Actor Framework from the bottom up but I just cannot wrap my head around implementing it on this scale. Everything is so deeply encapsulated that I cannot figure out how to actually DO anything! LapDog allows me the freedom to implement a moderate amount of LVOOP without having to wrap every aspect of the program into classes and messages.
      I know that's a mess of vague questions for a single post, sorry! I'm new to all this.



×
×
  • Create New...

Important Information

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