11-21-2018 03:53 PM - edited 11-21-2018 03:59 PM
@billko wrote:
... And this is why I'll never be a CLA.
I have exciting news! Nothing in that post has anything to do with passing a CLA exam. Yay!
To comment on some of the above, request-response is an important pattern regardless of how its implemented. As I recall, actor framework just recommends against the blocking form, which I think is good advice in general. The alternative would be that process A requests process B do something. Then it waits for either a timer to expire or a message. If the timer expires, it asks B to do the same thing, potentially with an ID to avoid duplicate effort (although it would be nicer if B had internal state and knew not to do the same task twice). If A gets a message, maybe its a message from B, and maybe it says that action was completed. If so, it can move on with its procedure. If not, it goes back to waiting. A big reason for this is that if you go for the blocking form but have bounded queues you can easily lock up your system if you aren't careful, either because B couldn't get the message, A's queue was full and so B couldn't respond, or whatever.
11-21-2018 07:05 PM
@smithed wrote:
@billko wrote:
... And this is why I'll never be a CLA.
I have exciting news! Nothing in that post has anything to do with passing a CLA exam. Yay!
To comment on some of the above, request-response is an important pattern regardless of how its implemented. As I recall, actor framework just recommends against the blocking form, which I think is good advice in general. The alternative would be that process A requests process B do something. Then it waits for either a timer to expire or a message. If the timer expires, it asks B to do the same thing, potentially with an ID to avoid duplicate effort (although it would be nicer if B had internal state and knew not to do the same task twice). If A gets a message, maybe its a message from B, and maybe it says that action was completed. If so, it can move on with its procedure. If not, it goes back to waiting. A big reason for this is that if you go for the blocking form but have bounded queues you can easily lock up your system if you aren't careful, either because B couldn't get the message, A's queue was full and so B couldn't respond, or whatever.
LOL I know that's not the focus of the test. I might even be able to pass the test with a bit of luck, but at each rung of the ladder I climbed, I made myself a promise that I wouldn't just pass the test, but that I would represent the title with integrity. I feel I am doing justice to the CLD title; I definitely would not be comfortable with a CLA title right now.
11-21-2018 08:33 PM
Thats definitely something I can get behind
11-22-2018 09:02 AM
Bear in mind that any simplistic reference-sharing approach you mention is prone to a whole bunch of race conditions if you don't introduce a proper locking mechanism. Locking makes your parallel jobs into sequential jobs (I'm oversimplifying a bit).
A message handler (pick whichever flavour you like, several have been mentioned int his thread) will handle this in a different way, but the end result should be race-condition free due to the sequential execution of "commands".
Regarding User Events, there's no problem using these for feedback. I don't quite follwo your problems with encapsulation.... Assuming it means having the API become a requirement of both sides of the communication....If you want to encapsulate the messages, you can define an abstract object "message" which exposes a "Send" command. Pass this to the code which needs to signal something and voila, your code no longer needs to know anything about user events. You can even switch between events, queues, notifiers, smoke signals as requirements change. On the receiver side (VI) you can handle the objects accordingly (depending on the method you choose). If you're efficient lazy, then you can simply define a single message of type Variant and do the heavy lifting elsewhere. One thing to remember is that the listener declares the communication path. This is an important aspect of the Actor Framework. The writer should receive the communications channel to the listener as a parameter, not the other way around. Otherwise you have problems with pathway lifetimes on shutdown.
11-22-2018 03:06 PM
@Mark_Yedinak wrote:In fact, we mix many different architectures in our system including actor framework. We look to see which design pattern or framework works best for a given system component.
In contrast, I always recommend picking one framework and mastering it, rather than using multiple. But get a feel for what is available before picking one to master.
11-22-2018 03:22 PM
@smithed wrote:The alternative would be that process A requests process B do something. Then it waits for either a timer to expire or a message. If the timer expires, it asks B to do the same thing, potentially with an ID to avoid duplicate effort (although it would be nicer if B had internal state and knew not to do the same task twice).
I also recommend one guard against overcomplexity in messaging interactions. Timeouts should be long enough that they kick in only on a true system failure, and thus trigger only error or shutdown. Imagine the pain if every subvi needed retry-on-timeout, with internal state to prevent duplication; don't let messaging be more complicated.
11-23-2018 02:51 AM
@patrick.wright wrote:
Are there any good methods for doing something like this in LabVIEW? I would potentially want the ability to add any number of parallel VIs that all can act upon and receive updates from the same object.
Thank you!
This is basically why G# was invented. LV objects with data as DVR so you get reference based objects. Check it out on VIPM. You'll also get a neat Icon creator and some other helpful Tools. I like the automatic Creation of folders for a class and the Icon editor especially.
/Y
11-23-2018 03:18 AM
You've opened a can of worms here!
There are many ways to achieve what you desire: perhaps DVRs or maybe more simply a non-reentrant VI.
The built-in OOP features of LabVIEW do indeed pass objects by value... but for good reason!
11-23-2018 06:25 PM - edited 11-23-2018 06:29 PM
@drjdpowell wrote:
I also recommend one guard against overcomplexity in messaging interactions. Timeouts should be long enough that they kick in only on a true system failure, and thus trigger only error or shutdown. Imagine the pain if every subvi needed retry-on-timeout, with internal state to prevent duplication; don't let messaging be more complicated.
For part of that, what I was skirting around the edges of was idempotence. If the system has an "externally" exposed messaging interface, the safest way to implement that to make sure that if the user presses send 10 times, nothing bad will happen.
Also, you're definitely right -- my description is I think of one of the more complicated cases. Theres almost always a better way. I do disagree with your statement about shutting down on timeout, but I almost exclusively use network messaging between headless automation systems so I'll leave that be.
11-24-2018 02:47 AM
@smithed wrote:
Also, you're definitely right -- my description is I think of one of the more complicated cases. Theres almost always a better way. I do disagree with your statement about shutting down on timeout, but I almost exclusively use network messaging between headless automation systems so I'll leave that be.
Ah, I was considering inter-process communication within an app, where message transport can be relied upon. Unreliable networking is more complicated. Depends on the method used; your suggestion would be a good strategy to work with UDP messages, but not right for a TCP connection.