mje Posted February 19, 2009 Report Share Posted February 19, 2009 I've created a framework class which I've used a few times, and tweaked it enough that I think it might be reasonably stable. It's a simple message pump/loop class. It essentially implements the consumer half of what LabVIEW calls a Producer/Consumer Design Pattern, but it can fit into several frameworks when you think about it. At it's most basic usage, you define a child class with some arbitrary private data, then override ProcessMessage.vi to operate on that data in response to messages. Messages are strings, and parameters are passed to (and returned from) the loop as an Object. This means that you'll likely have supporting data classes defined that allow you to pass relevant data to and from your message handling loop. Attached are two files: Contains only the class files. Contains the class files, and a project that has 3 examples to get you going on what the class does and how to use it. Some thoughts: I'm not sure the reentrancy of some of the VIs is the right thing to do. The MainLoop has to be, since it must be able to exist in multiple places if more than one version is running. Similarly, GetMessage has to be reentrant since it's the VI that the loop blocks on when the queue is empty, every running loop needs it's own copy of this VI. The other VIs, I'm not convinced that reentrancy is needed (ProcessMessage, InvokeCallback, Idle, HandleError). I'm leaning to yes for reasons I won't get into here, but I'll see what any of you have to say, if anything. I also flipflopped a few times on how to handle parameters. Objects are still "messy" in my opinion in LabVIEW, mostly owing to the fact that native data types don't inherit from Object. So even for simple parameters, you're forced to define very simple classes, which I often call "Static Data Classes" since they're often just wrappers around a single native LabVIEW type. Using a variant might be simpler, but I figured since this is an OOP based approach to a messaging framework, it's probably more elegant to keep it all object based. Every time I write another "static data class" though, I curse this decision, there's even a few of them in the examples, see the Int32 class...take a wild guess as to what it does. I still haven't checked the overhead involved in SendMessage.vi, where a notifier is created and destroyed with each call. But I can't seem to think of an elegant way of re-using a notifier where a previous value won't run the risk of triggering a race condition. I'd really like to use an Enum for a message, but again, LabVIEW types not inheriting from Object kills that idea. I thought of using my own class that I define, but that just gets messy when using the pump VIs on the block diagram since there's no native way to deal with class constants. -Michael Quote Link to comment
ragglefrock Posted February 20, 2009 Report Share Posted February 20, 2009 Nicely done! I like the encapsulation above all. It's a simple framework to use on the top-level. I also really like the idea of passing unknown messages onto the parent class. This is an interesting implementation for handling messages. You could probably architect it another way that wouldn't involve requiring each Message Handler override to call the parent method in a default case, but right now I can't think of exactly how to do that. Other areas to explore might be to allow different types of callbacks such as user events, which are useful for code that already has an event structure set up. Perhaps there's a way to dynamic dispatch this functionality. Quote Link to comment
Aristos Queue Posted February 20, 2009 Report Share Posted February 20, 2009 QUOTE (ragglefrock @ Feb 18 2009, 11:05 PM) You could probably architect it another way that wouldn't involve requiring each Message Handler override to call the parent method in a default case, but right now I can't think of exactly how to do that. Nor can I, which is why I posted http://forums.lavag.org/Providing-a-template-for-overrides-t13289.html&view=findpost&p=58591' target="_blank">this. Quote Link to comment
mje Posted February 20, 2009 Author Report Share Posted February 20, 2009 QUOTE (ragglefrock @ Feb 19 2009, 12:05 AM) Other areas to explore might be to allow different types of callbacks such as user events, which are useful for code that already has an event structure set up. Perhaps there's a way to dynamic dispatch this functionality. Great idea. Initially I was using events as a callback since the first few implementations went along side event-based producer loops, but I realized the necessity for a whole loop construct might be limiting the use of the class. However, your idea of supporting multiple callback types via a dispatch really intrigues me...I'll have to do some exploration and see what comes out. Thanks for the feedback! -m Quote Link to comment
JCC Posted February 21, 2009 Report Share Posted February 21, 2009 Hi MJE I would like try your framework, but could you save it in LabVIEW version 8.5? Thank you :-) Quote Link to comment
mje Posted February 21, 2009 Author Report Share Posted February 21, 2009 Here's an LV8.5 version: When doing the export, I've realized there's a dependency on the OpenG Error Tools, so you'll need that installed. This goes for the downloads in the original post as well. Quote Link to comment
mje Posted February 23, 2009 Author Report Share Posted February 23, 2009 Well, I really liked your idea, ragglefrock, and it turned out working it onto the framework proved simple enough. Attached is an updated 8.6 file: And a legacy 8.5 file: The OpenG Error Tools dependency is still there. There's still no example dealing with callbacks, but as before MessagePump::SendMessage.vi still wraps a callback up if you want to take a look. Basically callbacks have been abstracted into a base class called...get ready for it....Callback. Crazy I know. The class defines a dynamic method DoCallback.vi, which is called by the framework after every message has been processed, and by default does nothing. Derive the class though and implement the method and voilĂ ! Instant signaling of whatever synchronization routine you wish. I threw in three classes encapsulating notifiers, user events, and even one for a VI call, but nothing's stopping a user from creating others. All in all, I think I like this change, it hasn't added much complexity, but has definitely enhanced the utility of the class. By the way, is it normal I can't edit the original post to update the zip files for download? -m Quote Link to comment
mje Posted March 27, 2009 Author Report Share Posted March 27, 2009 Updated again. Download File:post-11742-1238072753.zip The OpenG Error tool dependency still exists. The class now handles initialization automatically, though the methods are still exposed through the public interface in case a child class needs to have it done manually. Examples have been updated to show this change. The stop mechanism has also changed to allow the signaling thread to optionally retrieve the data context of the consumer loop. This is mainly an update to demonstrate an undesired behavior (possible bug) which I'll post about in another thread. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.