Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Controlling parallel continous loops in actor core

Solved!
Go to solution

I have a GUI actor that has to be responsive to user events while continously updating a waveform graph.

The front panel objects (buttons etc.) are handled in a user event structure inside a while loop. Each event case only sends messages / fires other events etc.

The continous process of updating the waveform graph is handled in a seperate while loop. The data for the waveform graph comes from a queue that another actor's actor core enqueues on.

My question is how do I handle communication between the event structure and the data processing loop? I want to interact with the processing loop so I can do things like pausing the graph, changing which queue it receives data from etc.

At the moment I have an internal queue on which I enqueue string elements (inside each event case) and in the data processing loop I dequeue these strings from the internal queue. Inside the processing loop I have a case structure and the dequeued strings are used as the case selector. In order to keep the while loop (processing loop) responsive I have to dequeue one "message" from the internal queue, act upon it in the corresponding case, and then explicitly enqueue the next "state" on the internal queue. E.g. if I want to continously update the waveform graph I have to (inside the case structure) dequeue a data element, wire it to the waveform graph, and then make sure I return to the same case by enqueuing the same state on my internal queue (sort of like a standard state machine).

The image below should make it easier to understand what I just described.

Note the internal queue that's shared between the loops called "internal_queue_gui". Inside the event structure the next state of the processing loop is enqueued (e.g. "Data available")

Note also that the processing loop has to enqueue the next state on the internal queue like previously stated.

While this approach seems to be working I don't like the "state machine" feeling it has. I would prefer if I could start a "dequeuing and graphing loop" once and leave it running until I decide to interrupt it for whatever reason.

Gui actor core.png

Another approach that I tried was to incircle the "dequeue and update waveform chart" in it's own while loop inside the "Data available" case. The downside to this approach is that it makes the outer while loop unresponsive and necessitates that the inner while loop (that dequeues and updates the chart) can be stopped by a local variable or similar.

0 Kudos
Message 1 of 20
(26,462 Views)

One way is to put the data SR in one of the actor's methods. Then when data is available, send the data as a User Event and put the Chart in the UE structure.

0 Kudos
Message 2 of 20
(5,469 Views)

I haven't taken the time to read through the original post in detail and look at the code directly, but the mention of a shift register (SR) in the context of the Actor Framework raises an alarm. AF is designed to launch dynamic, multi-instance actors, and methods on LV classes must use shared reentrancy. That means shift registers are land mines in your code. As a matter of best practice, never use a shift register or feedback node in an Actor Framework class method; instead, store that information in an object property to be popped the next time the method runs on that object.

Message 3 of 20
(5,469 Views)
The continous process of updating the waveform graph is handled in a seperate while loop. The data for the waveform graph comes from a queue that another actor's actor core enqueues on.

The data acquisition actor sends messages directly to the waveform loop?  This is (imo) a mistake and is causing your difficulty with the waveform loop.  The data acquisition actor should send the data to UI.ActorCore, and UI.ActorCore should forward the data to the waveform loop.  Implement the pause functionality in ActorCore by not forwarding the data to the waveform loop.

The waveform loop doesn't need any message handling functionality.  It can be as simple as a dequeue feeding the data into the waveform indicator.

Message 4 of 20
(5,469 Views)

Arg - right, David. Kaspercj: Drop the SR for the queue and find another way to store the data (if it needs to be stored) - such as in a DVR. The Queue-in-SR is ok if the queue is obtained in Actor Core and entered into the actor's private data. But the way you're using the queue in the diagram above makes me think you don't really need a log, here.

0 Kudos
Message 5 of 20
(5,469 Views)

^^^ Like he said

If you want an example, take a look at the Angry Eagles project.  You could use a queue or a notifier to display the data (depending on where you want to store any "buffered data" and how you want to display it).

Angry Eagles DVR with Image.png

CLA, CTA
0 Kudos
Message 6 of 20
(5,469 Views)

David Staab wrote:

...methods on LV classes must use shared reentrancy.

Wait. This is statement is not generally true for LVOOP class methods -- do you mean, this is a requirement within the Actor Framework to create shared re-entrant methods?

0 Kudos
Message 7 of 20
(5,469 Views)

It's not required by the framework. It is, in my mind, part of the point of writing multiple-instance actors.

Oops - Staab's question.

0 Kudos
Message 8 of 20
(5,469 Views)

JackDunaway wrote:

Wait. This is statement is not generally true for LVOOP class methods -- do you mean, this is a requirement within the Actor Framework to create shared re-entrant methods?

Thanks for forcing me to clarify down to the smallest detail, Jack.

  • Message.lvclass:Do.vi is shared reentrant. That means your overrides of it must be shared reentrant, too.
  • VIs with dynamic dispatch terminals, if they are reentrant, must use shared reentrancy.

Actor methods in AF don't have to be reentrant if you guarantee that only one instance of that actor will ever be running at a time (either by application design or by the design of the actor).

  • If you have the possibility of multiple instances of an actor running, then every dynamic dispatch method on that actor must be shared reentrant.

If you design your actors to be overrideable or to inherit behaviors through a dispatch hierarchy of your design, you'll end up needing to design actor methods for shared reentrancy, which means avoiding FNs and SRs.

Message 9 of 20
(5,469 Views)

David Staab wrote:

JackDunaway wrote:

Wait. This is statement is not generally true for LVOOP class methods -- do you mean, this is a requirement within the Actor Framework to create shared re-entrant methods?

Thanks for forcing me to clarify down to the smallest detail, Jack.

  • Message.lvclass:Do.vi is shared reentrant. That means your overrides of it must be shared reentrant, too.
  • VIs with dynamic dispatch terminals, if they are reentrant, must use shared reentrancy.

Actor methods in AF don't have to be reentrant if you guarantee that only one instance of that actor will ever be running at a time (either by application design or by the design of the actor).

  • If you have the possibility of multiple instances of an actor running, then every dynamic dispatch method on that actor must be shared reentrant.

If you design your actors to be overrideable or to inherit behaviors through a dispatch hierarchy of your design, you'll end up needing to design actor methods for shared reentrancy, which means avoiding FNs and SRs.

+1 and thanks for clarifying.

0 Kudos
Message 10 of 20
(5,469 Views)