03-30-2020 09:42 PM
Thought I might explain the bigger picture, to justify my design choices. I have several TCP-controlled controllers I'm talking to in not especially fast but kinda-sorta high reliability application. Meaning that I need to verify several times/second that the controllers are working properly, otherwise I need to shut everything down tout suite or bad things happen. I had been using timeouts native to both queues and event structures to time things, which was working fine. But then I needed a couple of timers that wouldn't block execution - event-based (obviously I thought), but shared between multiple processes. So - I thought it would be a fine time to introduce myself to OOP and build a timer class, and use those objects to time the controllers instead of the queue and event timeouts. Ahhh, but then it became clear that several processes need to talk to the same timer, which wouldn't work with 'forking' a class wire to talk to the multiple processes. Hence my so-far-incomplete introduction to DVR's.
So - what I actually need - maybe 8 or 10 timer objects where each timer can be be shared between 2 or 3 different processes. 'Shared' meaning that, say, 3 processes start the same timer - the timer expires when the time expires from the first start time. I.e. the later calls are 'locked out' - they have no effect. When a timer expires, it needs to fire an event to a process (I call this "External Event" to distinguish from "Internal Event" that the time is actually based on timing out).
03-31-2020 12:12 AM
I'd take a look at the Actor Framework.
It's not exactly "entry-level" OOP, but it might fit your problem well.
The learning curve might be a bit steep, so you'd have to assess how much time you have to learn/test/experiment, but there's some good documentation available online, and examples and so on.
Effectively Actors are running asynchronous classes that receive and react to Messages. You can spawn multiple distinct copies of an Actor, or spawn one and share their "enqueuer" (post box/address) between sections of code (if you want), or some combination (e.g. 8 or 10 Timer Actor.lvclass objects with the enqueuers branched 2 or 3 different places).
Be aware this highly asynchronous model requires some rearrangement of thinking though... by default, nothing is blocking and you shouldn't request things from Actors in most cases.
03-31-2020 01:41 AM
I don't see the need for a DVR here. Have a class with a public user event and an 'occupied' boolean. At a Start function, set occupied to true and Create user event and sends it back. Spawn an asynchronous VI that only waits until timed out and sends the user event.
Did i miss anything?
/Y
03-31-2020 06:23 AM
Thanks for your good advice, y'all - got much much more to learn now. NI has made their online training classes free right now - since teleworking because of COVID-19, I'm gobbling up as much good training as I can while I can!
03-31-2020 07:09 AM
Yamaeda - 1 question - does your approach solve the problem of forking the class wire so that multiple processes can 'share' the same class object?
03-31-2020 07:25 AM
It depends on how you implement it. A User event thread can easily be split and'll work. I'll have to do a test. 🙂
03-31-2020 09:09 AM
If you want reference based classes, G# uses DVRs for all class data. 😉
But an example using DVRs, which you'll need if it's specifically the class wire you want to split, is attached as LV2017.
03-31-2020 09:13 AM
Wow, I've got Lots & Lots to learn. Fishing thru things, came across these:
https://lavag.org/topic/10666-labview-oop-by-ref/page/2/
03-31-2020 09:43 AM
Very grateful Yamaeda, this is very helpful. Very interesting to me, searching back to around September 2009, lots of passionate investigation and opinions around DVR's, by-reference programming, What-LabVIEW-Really-Is discussions between the Big Dogs of the LV world. My old neurons are getting thoroughly thrashed, and I'm loving every second.
03-31-2020 11:16 AM
This is fantastic, Yamaeda! Guess I was stuck on implementing these ideas. Couple of minor questions:
1) What data would you consider private? From the red key glyphs I assume all 3 elements in the class control. And the two public data are the "Timer event" refnum and the Wait(ms), correct?
2) (newbie question) In the Init VI I notice you 1st got the name of the timer.vi to give to the Open VI Reference function. But you already gave it a strictly typed VI reference - why is it necessary to also give it the name of the VI? Isn't that 'already contained within' the VI reference? The Help says "If you wire a strictly typed VI reference to this input, the connector pane of the VI specified by vi path must match the connector pane of this input." I'm a little muddled on this... Ahh, I'm answering my own question - "type specifier VI Refnum (for type only) determines the connector pane information and data type of vi reference." - so the type specifier is like a function prototype, defining the arguments and value of a function...