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