This is a major upgrade for the Actor Framework, introduced at NI Week 2010 and again at NI Week 2011. This 3.0 release breaks backward compatibility with the earlier releases. Many thanks to the users whose suggestions contributed to the considerable improvement in this latest revision. Major changes:
* Conpane of Actor Core.vi is much simpler and less error prone.
* System now backed by a priority queue, enabling emergency stop to be implmented cleanly.
* Error handling changed. Callee actors now have more control over the errors that they propagate to their callers. Caller actors now have more choice in how to respond to errors from callees.
* Actor's own queue and its caller's queue are now packaged inside the actor object, making Do.vi conpane considerably less complicated and making it easier for any method to send a reply to the caller.
This revision essentially achieves all the goals that we had laid out for the Actor Framework running in a single process. We expect any further changes to remain backward compatible with this revision as long as the AF remains a single-process architecture. When we begin introducing actors that can exist across the network from each other, we believe that those changes can be made fully backward compatible. In any case, this is the version we expect to maintain for quite a while to come.
The Actor Framework white paper is also newly revised. You can find it here.
[EDIT] Version 3.0.7.14 posted. It includes a small tweak: on the diagram of Launch Actor.vi, I changed the 0xC8 constant to 0xC0, which makes this version of the framework compatible with the upcoming release of LabVIEW 2012. The 0xC8 setting should have returned an error in LV 2011 but did not. In LV 2012, it actually does return an error.
Is there any chance of the existing AF demonstrations being updates so that they are compatible with the 3.0.5 version of the framework? Are there any new examples in the works?
Yes, there's a chance. 🙂 Unfortunately, this is a totally not-on-the-official-payroll project for all of us at NI who are working on it. Even the tech writer who reviewed the white paper did it on his own time. We're trying to get NI to take this as an official project, but that hasn't happened yet. As such, the usual NI quality markers of examples, tools, documentation, etc, are coming out in fits and spurts as we have time.
We thought about holding the 3.0.5 until we could get all the examples updated, but decided ultimately that there were enough projects that users had told us about that really wanted to get started soon with the framework, and we wanted them to be able to proceed with the revised version. It'll probably be a few weeks before the Message Maker and the examples are rev'd to match.
I've been impletmenting the updated Framework 3.0.5.10 and discovered a condition that would cause the Launch Actor.vi to wait indefinately that originated in the Actor.vi. If the Pre Launch Init or the Obtain Priotiy Queue VIs produce an error, then the Launch Actor.vi will never get a response and the Actor.vi will complete execution. I am tempted to say that the Pre Launch Init.vi would be better placed after the Enqueue, that way if the Init produces an error then the calling actor will recieve the Lask Ack message, instead of waiting indefinately.
I feel dumb. Looking at my test cases, I only checked successful uses of PreLaunch. Basic dumbness.
It can't be after the Enqueue. That would defeat the purposed of PreLaunch -- it needs to be something that makes Launch Actor return an error. The easiest fix would be in Actor.vi, on error, to Release the queue-of-queues. The only drawback there is that no meaningful error is communicated back to the caller.
I may have to back out PreLaunch until we can redesign it a bit.
Ok, I posted a fix. It's not the best fix, but we can spend time looking for a better one because any further changes would be behind the scenes. This at least gets the functionality working right.
Thank you, rpodsim, for checking this out.
Where could I get a AF for LV 2010?
I am working on it. I have done the port but not tested. You are welcome to my uncompleted effort. Please PM me with an email I can send a zip file to.
That goes for anyone interested, PM me and I will send you a copy. This way I can update you on any changes I had to make to the port get it working.
Kurt
Quick question.
No1.
The priority queue is scoped private, is the intention that all priority queues are created by Actors? This means that the initial call will not have a send to caller queue.
~Jon
Replying to JonKokott:
A) Use the "Message Queue Pair" class Obtain and Release functions to get a priority queue.
B) The queue input to Launch Actor.vi is Recommended, not Required, so often your top-level VI can just launch the actor without needing to create a caller queue. The framework is fine with not having a caller as long as the actor that you launch is likewise ok with that. For some actors, that design works fine.
OK, I see now, I obtain a message queue pair (which appears to only instantiate one instance of a priority queue) read the "Send" queue, then pass it to the launch actor.
On a separate note, why is the message queue pair obtained in this way? Why can we not directly obtain the priority queue in the first place?
The message priority queue is exposed within the Actor class in the send to self element, but the send to caller is of the "Send to class."
Should the "send to self" priority queue always be wrapped up with init from existing before sending to another actor/caller?
~Jon
> (which appears to only instantiate one instance of a priority queue)
It instantiates both the Send Queue and the Receive Queue. That's the pair.
> Why can we not directly obtain the priority queue in the first place?
What if we stop using a priority queue under the hood? What if we change over to a completely different data structure? Exposing the priority queue directly breaks the encapsulation. It's a private implementation detail.
> Should the "send to self" priority queue always be wrapped up with init from existing before sending to another actor/caller?
You don't have any option to do anything else. The "send to self" is private to the Actor class and the only function exposed to the child is one that returns a Send Queue.
Thanks for all the replies. I really like this framework better than any other messaging system I've seen.
2 pieces of feedback for now...
#1 was deliberate.
#2 you're correct should be fixed, although since no one but the framework should ever call Do.vi, it doesn't matter too much. But I'll fix it up.
#1 was, as I said, deliberate. It is generally best practice to mark the term that matches the dynamic input as a dynamic output. In this case, I wanted to give the Do.vi the option to completely swap out what actor was in the loop. Why? It seemed like an interesting door to leave open. I have one subsystem, for example, that runs a piece of hardware. In the event of an error, it creates a brand new actor for a replacement piece of hardware. This has created some difficulty because I now need to tell anyone talking to this hardware to talk to the replacement or I have to leave the replacement running so it can forward all messages to the new one. But what if I just replaced the Actor with a new Actor?
I haven't actually tried it yet --- it's on my list of "interesting variants to experiment with". But there didn't seem to be any driving need to close that door since the callers of Actor Core are limited by the Protected scope.
Minor note: As you note, if we did make the output be a dynamic dispatch output, we would have to add a Preserve Runtime Class call after the call to Do.vi in order to guarantee that the Do.vi *didn't* swap out the actor. Without that node, the Actor Core.vi would be broken since we wouldn't have a type guarantee from dynamic dispatch input to dynamic dispatch output. That's a performance hit, however minor, I'd rather avoid, honestly.
I guess #2 exposes one small problem with the framework then. No one but the framework should ever call Do.vi, but there's no way to enforce that since the Actor needs to be able to call Do.vi (needs community or public scope), and Do.vi needs to be able to be overridden (cannot be community). Unfortunately, this means that Do is public when it shouldn't have that level of accessibility. Correct me if I'm wrong.
Your comment about #1 is very interesting and sounds pretty cool. Unfortunately, if we replace the object with the Do.vi, the actor may be swapped out, but I don't think it will swap Actor Cores since the originating object's Actor Core is the one executing. The only way to do this correctly, would be to get out of the Actor Core and launch the new object while maintaining the same queue interface between the old and new actor. Again correct me if I'm wrong. I understand if you haven't had time to fully vet out this idea. I'd be interested in seeing a mock-up if you get something like that implemented.
Really nice framework. I think there are multiple components that may be useful and reusable in other variants of this same type of framework. Kudos!
It isn't a problem insofar as anyone else calling Do.vi doesn't break the framework at all. It just isn't the intended usage.
> but I don't think it will swap Actor Cores since the originating object's Actor Core is the one executing.
You're correct. But not all Actors have an override of Actor Core. There's many that just have the standard message handling loop. Or perhaps a parent class defines the specialized Actor Core and provide enough dynamic dispatch hooks that any further children can keep executing the same Actor Core.
> I'd be interested in seeing a mock-up if you get something like that implemented.
So would I. 🙂 Subscribe to this community group... if I ever get around to it, it'll get posted here. The list of "things I'd like to work on" is long...
OK, for those that are interested in a LV2010 version of the Actor Framework, you can take a look here:
https://decibel.ni.com/content/groups/actor-framework?view=overview
It is a group I started to document my experiences with ActorFramework, but I never had time to do anything with it. I figured that that would be a good place to put an unofficial (not NI sanctioned) LV2010 version.
I just posted version 3.0.7. This is fully backward compatible with 3.0.6 so I have just replaced the file on the web instead of creating a new document. The new version improves the testability of Actors. You can see the Description section of the new VI "Actor Framework.lvlib:Init Actor Queues FOR TESTING ONLY.vi"
Mike Lyons: I did not make the Actor input to Do.vi be a required input. I'm going to save that for the next version where we decide to break binary compatibility. Since the required/not required nature of that terminal makes no difference to the framework itself (hence the reason no one detected it before you), I decided it wasn't worth breaking the compatibility at this time.
Version 3.0.7.14 posted. It includes a small tweak: on the diagram of Launch Actor.vi, I changed the 0xC8 constant to 0xC0, which makes this version of the framework compatible with the upcoming release of LabVIEW 2012. The 0xC8 setting should have returned an error in LV 2011 but did not. In LV 2012, it actually does return an error.
Does this mean that I will be able to import my AF based designs into 2012 without any further actions required?
No. After I posted that on March 1, we decided to break compatibility because of beta user feedback. See here:
https://decibel.ni.com/content/message/39562#39562
However, you can continue to use version 3.0.7 in LV 2012... that installs into user.lib, whereas the one that ships with LV is in vi.lib, and your VIs will load whichever version of the framework they are linked against.