Actor Framework Documents

cancel
Showing results for 
Search instead for 
Did you mean: 

Event Source Actor Package

 

Event Source Actor Package

New Version 2 for LV19 with Map of Registrants

 

Introduction 
I wanted to share with you a small example actor I wrote to help me with typical subscribing/registering actors.
I have separated the functionality of registering, generating and unregistering from events. These events can be generated by the event source actor and are automatically broadcast to every actor who registered using Zero Coupling based message.
Broadcasting mechanism is based on the names of events defined by the user.
Please have a look at the code, run the example and let me know what you think.
 

Usage
To create/use a new event sink user needs to:
1. Create or select Event classes to be used for passing data.
2. Create new messages from abstract Event Generated Msg.class, for handling events on the sink side.
3. Register for events with the new event class, the actors enqueuer and Zero Coupling based message for handling that event.
 
To create/use a new event source user needs to:
1. Create or select Event classes to be used for passing data.
2. Add Event Source Actor to data of your class or make your class inherit from Event Source Actor.
3. Fire events of specific types.
 
The code is quite efficient (faster than array search) because it uses a dictionary for storing registered actors and events.

 

ESA1.PNG

ESA2.PNG

 

ESA3.PNG

ESA4.PNG

 

 

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Comments
Active Participant PrimaryKey
Active Participant

No comments on the code yet? What do you guys think? is it something you would use? I find this really usefull in my own designs. For example I base whole device drivers for shared devices on this.

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Member Brainstorms
Member

Thanks for publishing this; I find it useful.  I needed a good Associative Array for LabVIEW in early 2015, and wrote a more full-featured implementation than the "NI Dictionary" library you've included (it was inspired by the ESF, but has diverged from using it as the core).  Following that, I created a framework for AF use that uses publish-subscribe as the main means of communicating data between actors, which is also somewhat more full-featured than your technique.  The only other thing for AA's I've run across is the LV Container Class that Chris Cilino published, but I do like the clean, simple implementation you have here.

Active Participant PrimaryKey
Active Participant

Would you like to share your code? I would like to see it if its not secret

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Member HB@BNT Member
Member

The http://github.com/HB-GSI/CSPP_Core contains the PVMonitor.lvclass. It is an abstract class. Derived classes, SVMonitor and DSCMonitor, implement the details for polling mode and event driven Shared Variable subscription. It dispatches corresponding derived PVUpdate Messages to enqueres of registered Observers.

The concept is the same as described obove.

Member Brainstorms
Member

My organization won't allow me to share the code, but I could describe my approach. My dictionary (which I call "Registry", not to be confused with the Windows OS Registry) was object-oriented, using a string key and an object value.  Internally, it uses variant attributes, and the registry started as an ESF object, similar to your dictionary library.  (That changed, in order to allow multiple instances of particular registry subclasses.)

The key design focuses on the items stored in the registry, not the registry itself.  Registry items are linked to registries, so they "know" where they're stored.  Being a class, I created a suite of methods for adding, removing, retrieving, searching, etc., which are inherited by item subclasses.  The subclasses are specific objects with specialized data & methods that add to the Registry item methods.  I also subclassed the registry item object to provide item locking features (to avoid race states on shared registries), and again to provide a consistent API for the common open-read-write-close behavior (making its subclasses good for managing refnum-based items, such as files).  The common API allows easy swapping of implementations, e.g., from queues to shared variables, with no impact to existing code.

Member Suda苏打!
Member

hi guys,i feel some trouble,i just learning AF ,some days,i can understand the NI AF demo ,(for create AF project temeplate ,)but i don't understand your example,so can you give me some advices? thanks

Trusted Enthusiast
Trusted Enthusiast

Hi Piotr,

Thanks for this code. It look really useful.

 

Am I right in thinking that the Event Source Actor doesn't have to be the data source? In the example the Example Source actor inherits from the Event Source.lvclass, but it looks like the data source only needs the necessary enqueuer to an Event Source inheriting Actor to be able to Generate Events. The Update.vi shows two methods to generate an Event, either directly by calling the Event Source:Generate Event.vi (which presumably is impossible from outside of the Event Source inheriting Actor, since the Object In would be inaccessible) and by sending a message to the same - which would seem to allow anything to generate an Event.

 

Is there an obvious downside to this I'm missing? I suppose it makes the data sender dependent on the ESA class, but so would inheriting from it.


GCentral
Active Participant PrimaryKey
Active Participant

I didn't even think about that but yes, you could have an actor generate events on the event source, and the could be both independent. Interesting idea 🙂 the only downside I see is that event based communication is already breaking the comms hierarchy and here you would be adding yet another layer. So the number of actors taking to each other would be higher than needed. If you make your source inherit from ESA you minimize the number of actors. If that's not a problem in your design you can do it your way 🙂

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Trusted Enthusiast
Trusted Enthusiast

Thanks for the fast reply!

 

I see what you mean about increasing the number of actors who're talking all over the place, but in my current design (for better or worse) several groups of actors are already down inheritance hierarchies that it wouldn't make a lot of sense to place the ESA into. I suppose it would be possible to create a separate ESA implementation for every branch, but then I have no advantages and a huge number of copied classes... If I alternately place the ESA at the top of the hierarchies, where it makes sense to place it, I end up with things that will never send or receive events depending on the ESA framework.

 

As it was, I had a 'DataWrapper' class and a 'DataWrapperReceiver' class using a similar ZC structure, but yours is much cleaner. I also planned on rewriting parts of it to use VIMs anyway, so this is a good opportunity to rip out the ugly and put in something much nicer. This might also be able to take over redirecting data and/or errors (which I've yet to implement a good handler for) to a logging Actor.

 

Thanks again,

Christian


GCentral
Active Participant PrimaryKey
Active Participant

Christian, please let me know if you need any help or if you have any feedback after using it for some time. I will try to make it even better 🙂

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Trusted Enthusiast
Trusted Enthusiast

I thought I had managed to kneecap myself with multiple inheritance woes, but it turns out once I took a little break and came back to it I was just over/under thinking. Now I have copied over a half-implemented Error Handler I'd tried to put in a reuse library and gotten it working quite neatly.

 

Next up - getting the data transfer mechanisms in place for easy switching of logging mechanisms. Can't wait!

 

I'll let you know if I come up with any additional requests or useful feedback with this framework but it seems few enough VIs to be understandable. I might suggest that the PDF didn't make it immediately clear how to build a suitable Event Generated Msg class Do.vi - the Read Event Data VI isn't on the palette and it seems to be a requirement for passing the data out. The documentation (Context Help) does describe this clearly (and explicitly) though, so once I took a look at the example again it was easy enough to get going.

 

Please keep linking to these kind of things on your LinkedIn - they're invariably interesting to read!


GCentral
Active Participant PrimaryKey
Active Participant

As per your suggestion I added the Read Event Data to the palette.

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Active Participant kosist90
Active Participant

Hello Piotr,

 

thanks a lot for this package!

 

I've played with it a bit, and let me share some thoughts about it.

I liked it, and I'd like to use it, b/c it could simplify some routines. It's easier to use, then Stream toolkit from Jon McBee (and by the way, I'm curious whether you've played with Stream?), b/c it handles specific task. But, I've got couple points:

 

1. Maybe, step-by-step instruction would better to update based on the example. Because, while reading usage, and trying to create my own example, just description was not enough - I had to manually check in shipped example, what are classes parents, exactly from which class to inherit, etc. Maybe, it's because I'm fresh to AF, but anyway, if you'd include to description exact class names to start with, I guess it would help with it.

2. What I've recently found, is that when I have some helper loop in Actor Core, then I need to stop it by User Event. And, for each actor I need to do the same routine - create user event, save to Actor private data, then generate event, destroy it, and unregister. Is it possible to create such an example using this Event Source Actor, which would handle those actions, or at least some of them and the rest would be called by ESA functions from function palletes? Then, such an actor would be highly reusable, b/c this routine with user events could be handled by this tool.

 

Thanks a lot!

 

Sincerely, kosist90

 

logos_middle.jpg

 

Trusted Enthusiast
Trusted Enthusiast

Hi Kosist90,

Hopefully Piotr can give a real answer, but my guess for question 2 is that it would be difficult to really automate this definitely possible to automate this (writing how makes it seem easier now I finished) - you could make a "Stop-Enabled-Actor.lvclass" to inherit from, just below Actor (or anywhere else in your inheritance hierarchy) but the ESA works by sending a zero-coupled message. Although the Stop-EA could define this message, and conceivably also what to do with it, you'd still need some stop control (by which I meant a boolean control stored by reference).

 

My best attempt would probably be to have the following methods in a Stop-EA implementation:

  • Read Stop State - returns a boolean value from private data by reference which can be wired to the Stop of a While loop. This could be protected scope, if you wanted
  • Set Stop State - needs to be public, to be called by the message which the class defines.

Then a message class, inheriting from Event Generated Message, which calls the Set Stop State.vi, and makes the boolean True.

You'd need to put the Read Stop State in every while loop you wanted to be able to stop though, and the property nodes to do it by reference would prevent inlining.

 

Your Event can then be registered for by the Stop-EA's Actor Core, and you'd create an Event (perhaps named Stop?) which doesn't need to take any data (unless you want to be able to call it with True and False, to send it with False to not stop, i.e. expensive not-quite-no-op). I'm not certain, but it might be possible to use the parent Event.lvclass for this, if you don't carry data - just wire the output of the Set Event Name VI to the registration.

 

Stop Core should unregister from the event, again in Stop-EA.

 

Another Actor can then inherit from Event Source Actor and be responsible for generating the event, possibly in response to a message sent by another actor as described in an earlier post, if you wanted your real 'Sending' actor to not inherit from ESA, for whatever reason.


GCentral
Trusted Enthusiast
Trusted Enthusiast

Hmm. I took a swing at this but can't quite get it working. Will take another look when I have more time - sorry, had hoped to post an example implementation but currently it isn't working.


GCentral
Active Participant kosist90
Active Participant

Hello cbutcher,

 

thanks a lot for your detailed answer!

 

Now I realize, that this topic could be solved much easier. Just, create an actor, which in Pre Launch Init.vi would initialize User Event with boolean data type, and store reference to it in its private data. In Stop Core.vi, this reference would be destroyed. Also, accessor method is needed to read this User Event reference.

Then, we create child of this class. By default then, in Actor Core.vi we can read reference of User Event from actor's private data, and use it to generate event, and register event for helper loop. In this case, we'll get rid off routine of create user event, store reference to private data, and destroy it; what is quite enough, I guess...

 

Thanks a lot!

 

But if you'll have time to implement the example, how you've described it, it would be interesting to check it...

 

Sincerely, kosist90

 

logos_middle.jpg

 

Trusted Enthusiast
Trusted Enthusiast

Attached are the 2017 version, tested (but with some dubious architecture decisions - I'm only CLD 😉 ) and the 2013 backsaved copy, which is untested but didn't complain (despite the Stall Data Flow.vim usage and plenty of Actor Framework. YMMV).

 

It uses a Reply Message (urgh) and has some unfortunate timing peculiarities (I think these are with ESA in general, not my specific test VI). In particular, you can't stop the Event Source Actor immediately after sending the Generate Event, because it then often seems to drop the event generation. In my specific test, there's also a FSS to prevent the Get Address.vi being called at the same time as the Launch Root Actor, since the First Call to Get Address also calls Launch Root Actor, and on subsequent calls it returns the enqueuer (FGV). This means that the first call can't be during the PreLaunchInit of another actor, because then you have Launch .. Actor inside PLI, which is forbidden and hangs. Probably in any not completely made up situation, you'd expect your Event Source Actor to be already running, so this would be ok. Alternatively, you can move the registration into Actor Core.

 

Spoiler
The reason for the two hours taken to debug what I would have thought was a simple idea turns out to be that my GlobalStopActor didn't have its inheritance path properly set. It kept dying every time it received a Register for Event message, which then would't allow anything to work. I continuously assumed I was creating a mess with the Reply message, or the boolean by reference, and so troubleshot those for quite some time before I checked the class hierarchy for the ESA-class. Oops!

 Turns out I can't attach. Will post to github and add link: https://github.com/chrisb2244/StopEnabledActor

 

p.s. I make no apologies for the missing documentation or indeed default icon in the Test parts - you shouldn't use these even as inspiration! Hopefully the icons for the main parts are suitable.


GCentral
Active Participant kosist90
Active Participant

Great! Could you, please, upload to github also 2013 version, please?

Trusted Enthusiast
Trusted Enthusiast

If you take a look at the 'Releases' there should be a zipped 2013 folder available.


GCentral
Active Participant kosist90
Active Participant

I've downloaded it, but StopEnabledActor-2013.1.zip contains anyway code in LabVIEW 2017 (b/c I can't open it in LV 2016 even...).

Trusted Enthusiast
Trusted Enthusiast

Sorry - seems I messed up the upload somehow. What you want is the zip file labelled "backsaved.zip", not the source files in zip or tar.gz, those are automatically created from the repository which is 2017 code.

 

Not sure why the original 'binary' upload didn't work. Apologies again.

 

Edit: New link: https://github.com/chrisb2244/StopEnabledActor/releases/download/v2013.1.1/backsaved.zip


GCentral
Active Participant kosist90
Active Participant

cbutcher, thank you for the example!

 

Somehow, when I press button Stop, actor does not stop - but the idea in general is clear...

 

Trusted Enthusiast
Trusted Enthusiast

Hmm. A global stop that doesn't stop. Sounds pretty useless. I opened the 2013 version from the above link in LabVIEW 2016 when I got to my desk and found what I think is the culprit.

When I was testing, I set AF_DEBUG_TRACE to True, which I guess slowed down the actor slightly. It seems that the boolean to stop is being read with a previous True value before the real value is available. Placing a Property Node in SubpanelEnabledActor.lvclass:Actor Core.vi setting the value to false before bundling the reference solved the immediate death of the helper loop spawning "Alive!" messages. As to not stopping at all, I would guess again a timing issue but can't seem to find it myself. Can you describe it a little more?

 

Edit: Made some possible changes and updated the link above.


GCentral
Active Participant PrimaryKey
Active Participant

I wanted to ask all of you subscribed to this thread, can you please tell me if you are using the event source actor?

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Trusted Enthusiast
Trusted Enthusiast

I'm using it at the moment in a possible Error Handling section of my application. 

 

I haven't decided for sure if I'll keep it there but it certainly seems to work with its stated purpose.


GCentral
Member felipe.foz
Member

Hi Piotr,

 

Very nice job you did there. I wonder why not so many people are commenting this.

Do you have any news on this implementation?

I am really considering using this approach in my next project. Although I have some questions:

 

 

1. Is there a special reason for the mandatory unregistration at the end? Is this to avoid any unknown refnum or there is another reason?

2. Could there be a way for avoiding passing the message class implementation in the do.vi for the Event Sink.actor?

 

The second question is the one I felt more uncomfortable, because I would need to know the implementation of the source in the sink.

Maybe I am just thinking too far, but it is worth trying to ask.

Regards,

 

P.S.: One last question If you add another source actor, would it run in parallel with the first? I mean, a second dictionary to handle the events from this actor is created? Sorry, I forgout about writing this last one, hopefully still in time.

Active Participant PrimaryKey
Active Participant

1. Unregistration is not that important. You just use it if you need to stop listening to something. You don't have to do it at the end of application, I think.

2. The sink and source are using Zero Coupling between them. This is the most flexible mechanism possible. There is no better way. What other possibility do you envision? Case structure is not a valid reply 🙂

3. Any number of source actors can be spawned in parallel. They are actors 🙂

 

I hope your next project goes great 🙂

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Member felipe.foz
Member

Hi Piotr,

Thank you for your answers, I got the point.

About the question Two (2) I did some research on the new malleable VIs for classes (works only from 2017 SP1 and later).

I tried to do some implementation here and it worked with the a modified version of the ESA, although I don't know if it can be scaled.

BTW, I am using the brand new LV 2018.

These were my steps:

 

In Parent Event.lvclass

- Create a dynamic dispatch method called Read Data.vi:

Read Data.vi Event.png

- In child Events I override this parent .vi with this implementation:

Read Data Override.png

- In the message implementation from Source I include the data type in the Class Cluster:

class Data.PNG

- An then created this Malleable VI for the the Do.vi - Called Read.vim, can be saved outside the classes. It uses the Read Data from parent.

VIM implementation.png

- In the do.vi, we implement this malleable vi, unbundling the message class data to know the type, the malleable vi will adapt for any data type for any "event generated msg" class:

do.png

 

I am pretty sure someone can come with something better, I did this tests quickly in this morning, and I don't know if this implementation can hurt any zero coupling principle.

I thought of including the data type in the registration process, and somehow automatically doing this typecasting, but I am not very expert with the dictionary stuff.

Hopefully this post will bring up many comments.

Regards,

 

 

Active Participant PrimaryKey
Active Participant

I do not advise malleable VIs because they are new, unproven technology with many bug. This approach also does not achieve anything spectacular in code simplification and or diagram real estate. I recommend you stay with the basic approach, which additionally promotes understanding on what is happening in the code and type safety. You just need to cast to the type you need. I would rather recommend, if you want to simplify code, to programmatically thru scripting create the methods. I can actually build a tool like this if there is enough people interested.

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Member felipe.foz
Member

Piotr,

I understand your point about malleable VIs, as it is new, NI want us to use it, and then find bugs.

For the second, I kind of disagree, it is actually nothing spectacular, but in this approach the Sink Actor does not need to know almost nothing about the Source Class. I don't know if there can be any different kind of source class with the same data type, but if your project grows, your are free from worrying about that. As I create new actors, I just need to know the data they expect and that the source class inherits from Event Generated Msg.lvclass. Maybe scripting it is the way out, but I always try to seek a more dynamic way of programming, not depending so much on other classes for my actors.

Regards,

Member Ironman_
Member

Sorry but I stopped reading after: "Make his actor inherit from Event Source Actor."

Active Participant PrimaryKey
Active Participant

May I ask why? There is a very easy option to use this package without changing the inheritance hierarchy, utilising the ESA as a component.

Piotr Kruczkowski
Certified TestStand Architect
Certified LabVIEW Architect
Member felipe.foz
Member

Hi Piotr,

After developing some code, I encountered the following situation.

Using your example, hypothetically if you have a third actor (a second source) and your sink needs to process simultaneously data from these two sources (like optimizing file writing). What mechanism would you use to wait for the second message and process the two set of data together? Queue? Or am I just writing nonsense stuff?

Thanks in advance.

Member SHowell-HAL
Member

Piotr,

 

I installed your library a while back and haven't had a chance to sit down and go through it from a practical approach, until now.

 

What an elegant way to decouple GUIs from reusable hardware and other modules! 

 

Great work, I am going to probably be using this quite a bit in my development. 

Steven R. Howell
A&T Sr. Electrical Engineer

3000 N Sam Houston Pkwy E
Houston, TX 77032-3219
steven.howell@halliburton.com
Member SHowell-HAL
Member

Register for Message.PNGRegister Event Sink Actors

I wanted to work on a VI that I could plug in and register all the actors that I wanted to receive events. Mine are strictly GUIs but I have another situation where I might utilize this for a database module listening for data updates and it would work just as well.

 

Before this VI runs, I launch and catalog all of my Hardware and GUI actors enqueuers. 

Steven R. Howell
A&T Sr. Electrical Engineer

3000 N Sam Houston Pkwy E
Houston, TX 77032-3219
steven.howell@halliburton.com
Contributors