Jump to content

drjdpowell

Members
  • Posts

    1,973
  • Joined

  • Last visited

  • Days Won

    178

Everything posted by drjdpowell

  1. Having just watched Mike's video it seems he is mostly using asynchronous messaging (via a User Event in his example Active Object). He is using a DVR to allow some of his API methods to modify the active object's private data, and those are synchronous (but fast). My (perhaps mistaken) impression of the differences of Mike's Active Object to mine are: 1) He uses a specific reply channel for all responses from the AO (a queue in his “Send Message To Process” Method Template), while I use multiple reply channels, provided with the incoming messages themselves or "registered" as an Observer. This means (correct me if I'm wrong) that VIs based on the “Send Message To Process” template would not work properly if multiple were called simultaneously in parallel, as there is no mechanism to route the separate replies to the correct VI. 2) He uses bare User events and queues, while I wrap all communication as "Messengers". This will hopefully allow me to substitute network communication when I get the chance to develop it, without needing to modify my active objects internally. I've been following the philosophy that the active objects should know the bare minimum about the specify communication channels they are using. My example AO given in the first post, for example, only knows that it is using a "Receive-type" incoming messenger (which could easily be TCP-based instead of queue-based), and knows nothing at all about it's outgoing communication (which could be queues, TCP, shared variables, notifiers, etc., and can be several processes instead of just one). 3) His active objects are interfaced with by an associated API, while I build messages to send to mine via the generic API of the parent "Send" class. This is a minor difference as he could just use his “Send Message To Process” Template, unmodified, to send messages, and I could easily create wrapper API VIs. I'm not sure which is a better way to do things. -- James
  2. I made the same design choice in my own version of object messaging. Though I'm also not sure if there isn't a problem with this way of doing things. One possible advantage of having a VI take the parent class is that you have the option of handling more than one message type. For example, the VI to get a String might work for both a String message type and a Variant message type, where the variant contains a string. -- James
  3. The alternative communication channel is done: an easy-to-use "Observer Registry" as illustrated in my active object design. Also, although my active object template is a simple queued message handler, one can use more complex designs like a producer-consumer, where the producer loop monitors the input queue and a "Sequencer" consumer does the synchronous calls to the spectrometer and sample handler. Then if the producer were to receive an "Abort" message, say, from the UI it could send "abort" to the spectrometer and sample handler, which would then error-out the synchronous call from the Sequencer. Admittedly, the need to keep the synchronous stuff away from the input queue receiver does illustrate your and mje's point about being careful with synchronous calls. -- James (off on vacation and internetless for the next week)
  4. Following on the "Self-addressed Stamped Envelopes" topic, I'd like to present a design of an Active Object using my messaging library. This template has the ability to both "reply" to messages and to allow "observers" to register for event updates. I haven't used this template yet (just wrote the observer-registration part yesterday) and I would appreciate any feedback before I use it in a real-world project (which I'll be doing after a weeks vacation). The example object, "PP Template" does the following: Responds to "Current Time?" with a text string of the current time. Sets the format string for the time by the command "SetTimeFormat" Starts generating "TimeUpdate" messages periodically on the period given in the command "AutoGenerateTime" Allows external processes to register as observers of the following events: "SetTimeFormat" received "Current Time" issued "TimeUpdate" issued "Macro: Exit" received (this is the shutdown command for the active object) All error messages Here is how a higher-level VI might create ("launch") and communicate with "PP Template": In this example we launch "PP Template", register a Message Logger (another active object) as observer of all published events, send a nonsense message "Blah Blah" just to demonstrate error handling, set the time format, and query "Current Time?" first synchronously(*), then asynchronously with the message reply going to the "Asynchronous Receiver" loop. Then we register "Asynchronous Receiver" as an observer of TimeUpdate events (and set the autogenerate time of these events). On pushing the "stop" button, "PP Template" is sent a "Macro: Exit" command to shut down. Here's what the Message Logger receives when we run this VI: And here is the VI dynamically launched VI at the heart of the active object. It's basically a message handler with eight cases; three of the cases handle the three commands, then there is a timeout case, an error handling case, a shutdown case, an "ignore null messages" case (not shown), and a default case to catch unhandled commands (and spelling errors). The way receiver timeout and errors feed into the message case structure is stolen from Daklu's Lapdog messaging library. Some details of communication with the active object: 1) The object is launched by dynamically calling the PP Template.vi, setting it's "Startup Message" control via a VI Server call, and then doing some handshaking messages between "Launch.vi" and the "Startup" and "Acknowledge Startup" VI's. This creates the incoming command messenger for the process (in this case it is a queue based messenger, but there is an alternate "Startup" VI for a User-Event-based messenger). Calling a "Send" or "Query" method on the active object calls the same method on the command messenger. There are two startup modes: when started as an "autoshutdown slave", the messenger is created inside the Launch.vi, which means that if the main VI goes idle, the queue reference will become invalid, which triggers a "MSRReceiverError" that shuts down the launched VI ("Message Logger" in the above example shuts down in this way). The other way creates the Messenger inside the "Startup" VI, making the active object independant of the Launching process. 2) Observer registration is handled by an "ObsReg" by-ref object, with two methods: "Registration", which filters out and acts on registration commands, maintaining a list of all observers for each event message (and sets for all events and all error events), and "Notify Observers", which accepts messages and sends them to all observers registered for them. Thus, it is extremely easy to publish new event types; just package a message for the event and pass it to "Notify Observers". 3) Reply-based communication involves a "return address" (a messenger or other active object reference) to be attached to the message, and the active object using a "Reply" VI to respond (in synchronous communication, the "Query" VI creates a single-use response queue to receive the reply). For error handling, the Reply VI will package any error in it's error terminal as an error message and send this to the return address (this is in addition to an observers being notified of the error). -- James (*) Please note the potential problems of synchronous communication brought up by mje.
  5. Synchronous ONLY is perhaps not a good idea, but synchronous messaging is good for synchronizing things. As an example, suppose I had a spectrometer and a sample handler for deploying samples to be measured. I might want to deploy a calibration sample, THEN calibrate the spectrometer, THEN deploy a sample to be measured, and THEN measure the spectrum of the sample. This would be trivially easy to do with four synchronous queries chained together by their error terminals. If either spectrometer or sample handler had a problem it would return an error message as its reply (such error appear on the error-out terminal of the Query VI). Of course, if either component needs to signal something immediately there needs to be a dedicated channel. In which case, neither my synchronous nor asynchronous "reply" examples work, since in both cases the communication channel is a part of the received message. I've been developing a third communication mode as part of a "Active Object" template: registering for event updates (the OOP "Observer Pattern") that would work for this. All three modes should be useful and can be used on the same active object. -- James
  6. For completeness, here a simple example of an asynchronous query, where the controller has its own incoming messenger, which it attaches to its outgoing message to Process A, allowing it to receive the reply asynchronously: This example also shows a User-Event-based Messenger. -- James
  7. I agree, and I've been trying to design my messaging system in that way, so that one can use it for simple things without having to understand everything that might be done with it. My original design goal was to be able to have processes that send messages without having to know whether the messages are being sent by queue, or notifier, or user event, or UDP or TCP. And for processes that receive messages to be able to transparently use network communication (TCP etc.) in place of local communication. That makes things simpler, not more complicated. And my initial goal for the Parallel Processes is to have a simple template for creating "speak-only-when-spoken-to" simple active objects that can be "queried" by higher-level processes. Thus the synchronous, command-reply communication (shown below with text-varient messages) was the first thing I developed (which lead to the idea of having each message carry it's own reply method): I find this synchronous communication to be more clear and simple to use than asynchronous. I probably shouldn't have first introduced my messaging design with the complex example of my first post, as one would start out (and perhaps end) with much simpler uses. Getting back to the more complex example of my first post, although the messaging is direct from A to B, all the routing and slave interactions are setup by the main VI. In my system, one can look at the creator of the process to see who is passed the wire representing the ability to communicate with that process (hopefully, there are only a limited number of such potential message senders). And I'm hoping my "Message Logger" can be developed into a useful debugging tool. Below, I've modified the Logger to add some tracing information (the call chain of the process sending the message and the message timestamp). -- James
  8. Yes, I nearly titled this conversation "Yet another messaging system". Looking at your "MessagePump" loop, I can see the great similarity, just with different terminology. My "MSG" message class contains a label (your "message identifier") and a "Send" object (your "Callback"); children of MSG add "Data" (your "parameters") of various kinds (the example I gave used a text-data message). "Send" is a virtual class, who's central method, "Send.vi", does nothing, but it's various children override Send.vi with different communication methods or other functionality. So far, I have Queue and User-Event "Messengers" (hopefully to be extended in future to a network-enabled TCP messenger); "Parallel Process", an active-object design that uses the messengers for communication; and "ObserverSet", an extension of Send intended for allowing multiple processes to receive ("observe") the same message. Here's an extension of my first example, where I've added a Message Logger (Parallel Process) that "observes" the messages to both processes A and B: Note that I made no changes to A, B or the Controller Loop; none of these processes are aware of the existence of the Message Logger. I've been experimenting with what kind of interesting functionality I can build into the Messaging system itself, while using only quite simple processes to message between. Here's a further modification of to example where I replace the "Controller" Loop with a "Metronome" parallel process that sends "MetronomeTick" messages periodically to the ObserverSet registered with it. I've used the ability of Observers to substitute an alternate message to have Metronome send the "SendTimeString" message to process A. Note that A, B and Metronome know practically nothing about each other. They don't use any compatible message labels and they don't know what underlying communication method they are using. Metronome needs to "send" updates to its ObserverSet, but doesn't know anything about the number or nature of observers, or that it's messages are being rewritten. I had originally started writing a parallel process that maintained arrays of registered observers, with arrays of alternate message labels, but realized that all this functionality could be built into a extension of the "Send" messaging class, and thus added for free to any (much simpler) process that can register one "Send" object for updates. In a hierarchal master-slave tree structure, like Daklu suggested, there is less potential for circular dependancies, as any synchronous messaging would always be from master to slave. And, of course, one needs a timeout error; here's my synchronous "query": -- James
  9. Hello,The recent posts about "Message Routing" has inspired me to mention a variation on this idea. In particular, I am thinking of Daklu's description of his "Slave Loops" that only communicate with their masters (requiring the master to "mediate" communication between slaves), and Mark Balla's Message Routing Architecture. I have been working on my own LVOOP Messaging system, one in which there aren't specified "output" channels; instead, each message can contain the method to rely or respond to it. Sort of a self-addressed, stamped envelope. This allows one to build a "hierarchical tree of master/slave loops" as Daklu suggests, but with the ability to direct messages to thier final recipient without mediation. A simple example: In this example, the Controller (master) sends a message to Process A (label="SendTimeString") with the attached reply address (command queue) of Process B, along with an alternate label, "CurrentTime", to be used for the reply message. Thus, Process A directly sends a message to Process B, with no mediating or routing processes in between, yet without either process knowing anything at all about each other (they don'y even use the same message labels). The Controller sets up the communication link between A and B, but doesn't itself need to handle the message. One can extend this into an "Observer pattern", where the Controller registers Process B as an observer of Process A's regularly occurring "TimeString" events, (complete with message relabeling to "CurrentTime"), again with neither A nor B having to know anything about each other. -- James
  10. I don't think you give that impression. It's not even close to complete (the four-hour time limit would be a killer), but I can show the statemachine with a case that is; the "Main Menu" when the user selects the "Fast Cash $50" option (see attachment). I found the ATM problem to be obviously calling for a state machine; it practically defines all the states for you. The problem equally seems to call for some LVOOP, again practically defining all the classes: "User Console" and "Account Database", with children "Simulated Console" and "Simulated Database" (ready for the eventual replacement with "Physical Console" and "Enterprise Database"). If I were to use a JKI-SM (though I wouldn't be allowed the template on the exam), I might instead have had "Macros" such as... "// Main Menu Card Slot >> disable Keypad >> disable Menu State >> Main Display Message >> Main Menu Wait for User Input Process Main Menu Input" ... with the "Process Main Menu Input" calling (if the User pushed this button) "Fast Cash $50", which would call "Withdrawal >> Complete". The QSM version would not be terrible but would be clearly poorer than a true SM. But this problem is very clearly definable as a statemachine. Most programs I write involve "do the task requested before returning to idle", with the complexity of the task being more easily broken down into sub-tasks than states. For complex tasks, JKI-style macros are quite clear and they're quick to write compared to wiring up subVIs. The subVI option is clearer than JKI-SM frames, and I can appreciate some of the other advantages you point out, but the real reasons I've started to use subVI's more and more lately is the advantages of OOP classes and dynamic dispatch. BTW, what do you think of the provided example solution to the ATM example test? The one where it's done with Action Engines. -- James
  11. Sorry, should have used a smilie of some kind. Not an effective smilie user. There. On a side note, I have just learned that there is a practice CLA exam and tried a go of it last night. Being an ATM program with obvious state-fullness I used a state machine, my first real one ever, I think! -- James
  12. Hi Daklu, Another of the problems with the bad "QSM" name is that there are many conversations where someone brings up "QSM" and it triggers comment about their flaws as true state machines, "state diagrams" and such, WITHOUT ascertaining if the original use of the QSM pattern was anything to do with "different responses to the same message depending its current state". I suspect most use (and certainly better use) is more similar to what you use your message handler for. It may even be intended (dare I say it) as a structure for programing without separating the UI from the rest of the code! We lesser programmers tend to do that. So I did get the mistaken impression that people were suggesting true state machines for all sorts of purposes that seemed to me to be a poor fit. You might be right. I think (lest I'm mistaken) that a QSM like JKI's is interchangeable with a QMH with appropriate subVIs (and the JKI-SM can meet your three conditions for QMHs). In my own use of the JKI-SM, my first uses definitely were flawed by too little use of subVI's, while lately I use a mix of mostly subVIs for low-level operations and frames of the case structure for higher-level ones. Your argument that case structures, loops and subVI's is clearer than a queue for complex processes is a much better one than your state-machine related criticisms; now your talking about what people use "QSMs" for. -- James
  13. You could also consider using a multi-column listbox and right-click menu, customizing the menu to the set of options available for the specific box right-clicked on, then write the selected option into the box.
  14. Hi Daklu, Most of your criticism of the (badly named) "QSM" is all down to the flawed design of using the same queue for messages to the QSM and "states" (really operations) within the QSM. This flaw may be common, but it is not inherent to QSMs, and templates such as the "JKI statemachine" don't have it. There is no asynchronicity in a properly designed QSM (your point 4), nor do producer loops directly initiate QSM "states" (point 1). As to better separation of the UI (point 3), I'm not sure ignoring messages is all that great an idea (I have visions of the annoyance my Users will have after pressing "start", and coming back 5 hours later to find the equipment just sitting there). Point 2 is complicated since a QSM isn't actually a state machine and thus isn't a good way to implement a complex state diagram. But how good is a true state machine at implementing a complex flow chart? Aren't you making the same error as "QSM for everything" people by suggesting "true state machine for everything"? Is a hammer a useless tool just because people have mislabeled it as a type of saw? -- James
  15. The flowchart tends to seem more intuitive to me for what I'm doing, so the badly-named QSM is good for me. Admittedly, this may be just a lack, on my part, of a clear understanding of the value of state diagrams. -- James
  16. Only thoughts: -- I would separate the changing of frames of reference (AB in A-frame --> AB in B-frame) from the inverting of the vector (since the later is then trivial) -- shouldn't the change of reference frame involve two relative angles? rather that the single angle your code snippet seems to have? -- James
  17. That is a flawed design, due to the use of the same queue for both internal operations of the lower loop and incoming messages from the event structure in the upper loop, leading to indeterminacy in the order of operations. Good design always uses separate queues. I, personally, would recommend anyone starting to use "QSMs" (how about "Queued Operation Machines", QOM?) to use a good template such as the JKI statemachine toolkit to avoid these types of design mistakes (which I sadly recall making myself). -- James
  18. For the benefit of Dannyt and others reading, "Queued State Machines" such as the JKI state machine are misnamed in that they are not actually state machines. True state machines are a different concept, and are what Paul_at_Lowell and Daklu are talking about. QSMs are more like queued command or queued operation machines, and thus the concept of a "macro" set of commands applies. -- James
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.