Helper 4

0 views
Skip to first unread message

Ling Baus

unread,
Aug 4, 2024, 1:31:09 PM8/4/24
to liesobolcont
Ifinally managed to write a little something about how we use helper loops in our applications. Feel free to take a look at -soft.com/blog/dqmh-actors-self-messaging-or-helper-loops/ and let me know if you have any further questions or comments

Nice post Joerg! I need to get round to writing mine! Your approach matches mine to a great extent. The bit that I've added is to have the helper loop enable/disable itself when the module is idle/active. So the timeout in the helper loop is set to -1 automatically when there's one or more messages in the message queue and reset to the helper loop period when the queue is emptied. That way I can be sure the helper loop never (or at least almost never) gets in the way of the operation of the module.


We're also using the second type of helper loop in a singleton module which manages (and provides the interface to) a cloneable module. The helper loop handles all messages coming from the cloneable modules (and any other external module we're interested in hearing from).


Now, this COULD be done using the main event handling loop of the DQMH, but I do prefer keeping the two loops separate - one loop for direct commands to the main module (i.e. the DQMH event loop) and one loop which I call the "External module event handler" which registers for the broadcast events of external modules...


One interesting thing is that you point out that you don't want the helper loop to get in the way of the operation of the module. So far, for most (if not all) of our modules with helper loops, I'd not want the module to get in the way of the helper loop. This distinction is definitely something to keep in mind when designing the module. Let's talk about this some more next week in Madrid.


When talking to some LabVIEW friends about this blog post, I was confronted with reservations regarding using the timeout event of an event structure for periodic actions. It was pointed out that NI's core 3 training recommends not to use the timeout event for any critical actions.


We're using DQMH for a motion application and the end user can physically move the motion stages around without software input. The helper loop makes the DQMH periodically poll it's controller for any change in encoder position value and then we can broadcast that out to the application to update any UI which shows system position in real time. The module already sends its positions out during moves so there's no need for the helper loop to run...


I would have to review the specifics of the LabVIEW Core 3 course to understand the exact scenario being described, but I can definitely see a recommendation to avoid using a Timeout event for handling "critical" events in an Event Structure that is also handling other "critical" events.


But in the case of a helper loop, the Timeout event *is* the critical event. As you mention above, it is critical that other requests *not* interfere with the operation of the helper loop (other than what was mentioned...enabling/disabling the helper loop, and the Stop Module request).


"Initially, we only supply a constant of the UI.System Message user event refnum for the event registration node. This allows us to create the corresponding event case. Beware that our helper loop is only loaded, but not yet armed."


1.) In my blog post, in the picture after the one you quote, you can see how I enable the event registration for broadcast events in the helper loop. I place the Obtain Broadcast Events for Registration.vi on the block diagram, wire its Broadcast Events cluster to an Unbundle By Name node, select the "System Message" user event refnum and wire it to the Register For Events node. This is the place where I get the constant: I pop up (right click) on the user event refnum wire and select "Create Constant" from the context menu:


2.) Drop the Broadcast Events--cluster.vi on the block diagram, and drag the "System Message" constant out of the cluster. Because the cluster is a typedef, you cannot move the constant out of it. You need to copy it out by keeping your ctrl-key pressed while dragging:


I'm writing an actor where I'm offloading a long task to its helper loop. That task needs access to the values of the actor's current private data, and then the actor needs to change private data depending on the results of the long analysis and the current private data.


My understanding is that actors are by value classes maintained in a shift register of actor core. Therefore in an actor's helper loop, which I create, I shouldn't make a second shift register with the actor's class wire -- that would create a copy of the actor's private data with all the potential bugs associated.


My issue is, within the helper loop's event I need access to the up to date private data of the actor's class. Now I thought about sending copies of the actor's private data when the event fires, but that has concurrency issues (if multiple such events are fired, and the first one modifies the private data the subsequent events will be making decisions based on stale data since I sent copies).


Do I want to send a reference to the actor's private data to the helper loop? Is that an Ok design within AF? I'm a little hesitant of that solution b/c now I have two things which might modify the actor's private data but maybe since helper loops are within actor its still "encapsulation". Not really sure...


If the data should more properly be state of the helper loop, move those fields out of the actor and into the helper loop. When the actor receives a message that needs to modify those fields, send a message to the helper loop (queue or user event) to do the action and modify the fields.


Interesting, so I've never considered having a separate state to maintain, that of the helper loop. I guess I was kind of gravitating towards actors are their own states so I should put everything in their private data. I guess I'm not seeing a downside to having long-task state data could go into the helper loop's shift register. Then periodically the helper loop fires off a message with the current state to the actor when the analysis finishes.


(My potential worry right now is a race condition where if in prelaunch init of a nested actor, a message is sent to root, and if root chooses to direct it to a helper loop, that root's helper loop might not be up and running yet.)


You don't have to worry about that. The communication channels are established even if the loops are not yet running, so the various "send" operations that you're wanting to do all succeed. The parent enqueuer is already established, and any link you create from parent Actor Core to helper loop will already be established by the time the parent receives the message.


Messages are handled in Actor Core (or, more clearly, the Call Parent Method node in your new Actor's Actor Core). Launch Nested Actor also doesn't return until Pre launch init returns, so if you have Launch Nested wired in series before Actor Core then you KNOW that Actor Core won't handle the new message until AFTER your nested actor has finished launching. The helper loops may or may not be running yet (it depends on where you put them of course). Like AQ said though, you're definitely not going to lose a message.


Just to sharpen my question, I'm not worried about losing a message. I'm worried about losing a user event that's fired by root but before root's helper loop, which has the event structure that's dynamically registered to handle the event, has begun to run yet.


The only thing that worked was killing the Brave helper process. Not sure of next steps, but I am happy with Brave, and am fully behind the project and its vision, so I am truly hoping there is a solution to this problem (looks like it has been around for a while judging by some of the hits I got in my Google searches).


Yes, I disabled the hardware accelerator, but the problem persisted for certain websites (i.e. WSJ online). I also identified an issue with Adobe Creative Cloud. After I deleted that, I have not had the accelerator issue with Brave.


Specs, Macbook Pro 16, 64 GB ram and 8 Core-i9. One of the contributing factors might be that I use an external monitor that is only HD (as compared to the retina display). The two tabs were on that monitor before I shut down last night, so there may be some problem with the graphics engine in Brave and the two monitors with different resolutions.

3a8082e126
Reply all
Reply to author
Forward
0 new messages