Jump to content

nileracecrew

Members
  • Posts

    7
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by nileracecrew

  1. That's very interesting. I've always tought the flush operation would reduce the queue size to zero. By the way, do you know if LV Queues are implemented internally as something like a C++ STL Queue or a Forward List?

    http://www.cplusplus...ce/queue/queue/

    http://www.cplusplus...t/forward_list/

    I can't speak for RT FIFOs, but I have read that the normal queues are implemented as circular buffers. Not sure how/when re-allocation happens, but I assume that once the buffer grows in size, it doesn't shrink back down. Hence the N-element enqueue/flush trick.

  2. Back to the original topic, I did find a significant caveat when using the method described above to change the object that a DVR refers to. Suppose I have a DVR that refers to a parent-class object. I replace the object with a child-class object, then later down the wire--works fine. Then, I try to replace it again with a parent-class object. The second replacement will fail since PRTC will (correctly) fail--a child-class object is on the middle wire, but I am trying to pass in a parent-class object.

    So, that is the case that LabVIEW seems to be protecting against: parent class DVR refers to a child-class object, and you try to swap in a parent-class object. I still don't understand why that's a problem. I'm guessing it's an implementation issue?

    I made a related cross-post on the NI forums to see if anyone there has answers.

  3. I haven't read through all the replies on this thread, but this comment jumped out at me.

    As an alternative, have you considered writing an instrument actor instead of using by-ref objects? Personally, I find actor-oriented programming much better than reference-based programming for multi-threaded applications. YMMV.

    I am starting to lean that way as well. In this particular case, it might create some headaches because of a need to coordinate and sequence multiple subactors. I am still trying to sort out the best approach. The actor model is new to me, but fortunately with this project I have the luxury of a little time to research and make a few prototypes before settling on an architecture. FYI, your Slave Loop post really helped my brain get around the whys and hows using actors, so big thanks for that.

  4. The code above though is deceiving because everything inherits from LabVIEW Object. If your DVR was of a class unrelated to Node List (other than the common LabVIEW Object ancestor) then the cast definitely fails, which would be the expected behavior.

    Agreed. I didn't have a suitable class hierarchy immediately on hand to make a simple example, so I cheated. Trust me that it works the same way with a user-defined parent and child.

    However there you have it, your example. I guess then the DVR can mutate in type, so long as the mutation results in a more specific run-time object? This seems...odd to me. I too can't help but wonder if that's intended behavior. Need some time to mull this one over.

    There is some strangeness here, especially when you read the LabVIEW documentation about using classes with DVRs and IPEs, and the fact that PRTC is required. Absent that though, this is how I would expect it to work. A child object is technically is of the parent type, and you can mix parent and child objects in arrays, clusters, queues, etc--as long as they are of the parent type.

    If you really want to blow your mind, as I alluded to in my question #4 in my first post, you can get rid of the PRTC by wrapping the object in a cluster:

    post-28228-0-92166000-1353905410_thumb.p

    There's a cryptic sentence in the "using references with classes" link above that says you can do this to swap objects without PRTC, but I'm not sure what's going on under the hood that makes this work, or even if it's supposed to work with child objects.

    • Like 1
  5. ps, Thanks for your reply. Based on what the LabVIEW DVR documentation says, I agree in principle with what you wrote. In practice it seems to do something else. I'm trying to figure out if this is expected behavior or not.

    I don't have a quick example to show a method override, but here's a stupid example that shows that the object mutates and preserves child class data. The DVR is a reference to an LVObject, but I use PRTC to stuff in a "Node List" object that has previously modified class data. Later on I get the object back, downcast it to Node List, and get the data out.

    post-28228-0-40710300-1353891345_thumb.p

    In a larger application I was able to call an overriden method from an IPE using a similar technique.

    • Like 1
  6. The PRTC primitive is a confusing beast. To understand what it does, you need to understand the difference between the wire type in your diagram, and the actual value type that's riding on that wire at run-time. You might have a wire type of "Pack", but the actual value riding on the wire at run-time could be a Pack object or any descendant class of Pack, including your PCPV4 class, among others.

    The DVR is used to operate in place, which means you need to ensure that the value on that wire is the exact same type as what was originally there. You might be accessing the DVR as a "Pack" wire, but there could be any child class of Pack actually riding on that wire at run-time-- you just don't know ahead of time. That's why you need to check at run-time what type of class is on the wire. The PRTC does this, whereas the other casting operators do not.

    Right, but PRTC does not throw an error if there is a child object on the wire. It only errors if the runtime class of the "in" object is higher in the class hierarchy than the target. I believe this is by design, otherwise you would break dynamic dispatch for children of the child. This is why I'm confused. If the parent DVR can't accept a child object, then PRTC is not going to stop that from happening.

    "OK" depends on what exactly you're expecting out of the construct you created. Do you expect to actually mutate the type of object on the wire at run-time? If so then I expect your code isn't quite doing what you hope. The PRTC primitive is there to enforce the value type definitely does not mutate at run-time. If the cast fails, then the run-time class from the middle terminal is used (NOT the wire type, but the actual value type that is riding on the wire). Hence the name of the primitive, it preserves the run-time class. Check the error out terminal if you fail to actually preserve the type.

    As far as I can tell, it does mutate. I can make a child object, modify its data, and stuff it as shown into a parent DVR without any error from PRTC. Later on, if I dereference the DVR, the resulting object is still the same child (even though it's on a parent wire) and will call overriden methods.

    I don't have time to get into any more detail, but I've done similar things to what I believe you're after. Basically you have a DVR of type "Pack", and what to be able to change the value in the DVR to mutate to an arbitrary child class of Pack, correct? In this case, destroy the DVR and create a new one. The two values are different types, it makes no sense to operate on the values in-place.

    The trouble with this approach is that it will break the DVR in the other parallel loops.

  7. I am trying to understand the requirements for replacing the object that a LVOOP DVR refers to. I've looked at these pages, but I'm still not quite sure I have a full grasp:

    http://zone.ni.com/r...lassrefswapped/

    http://www.ni.com/wh...er/9386/en#toc3

    I have what is essentially a LVOOP hardware abstraction layer: a parent class with dynamic dispatch methods, and a number of child classes that override those methods to provide the specific hardware functionality. In a single-loop application, I can initialize a shift register with a parent class object, and then inject a child class object onto that wire as needed.

    I am now working on a multiple-loop application, and need a way to serialize access to the hardware object across the loops. It seems like a DVR is the right tool for this. Here is a watered down version of what I am thinking of doing:

    post-28228-0-74704300-1353871817.png

    Here "Pack" is the parent class, and "PCPV4" is one of the child classes. In real life that case statement would be a state machine.

    Some questions:

    1) Is it ok to replace a the object that a parent class DVR refers to with a child class object? In my limited testing, as long as PRTC is there, everything works as expected: I can later dereference that DVR and it will act as if there is a child object on the wire: it will call overriden methods, maintain child class data, and so on. But maybe I am abusing something here.

    2) Why is PRTC needed? Even though the referred object gets replaced, the new wire is of the parent class type, so at runtime the object is already guaranteed to be of the parent class type or one of its child classes. PRTC doesn't seem to tell LabVIEW anything it doesn't already know.

    3) Eventually I will have multiple objects (not all of the same parent class) that I need to keep track of, so my thought was to make a DVR to a cluster of parent objects. Wrapping everything in a cluster seems to get rid of the PRTC requirement. Why?

    4) From what I gather from the two links at the top, there are more sinister problems related to swapping objects in a DVR, but I'm having a hard time understanding a) what those problems are, and b) how PRTC fixes them.

    Thanks for any replies.

×
×
  • Create New...

Important Information

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