Jump to content

Aristos Queue

Members
  • Posts

    3,183
  • Joined

  • Last visited

  • Days Won

    204

Posts posted by Aristos Queue

  1. I am hoping all of the collective knowledge of LVOOP here can help me out. I'm having an issue with dynamically calling external child classes from an executable. The parent classes is currently build in the exe. When saving those child classes with all dependencies, the parent class is also saved in the hierarchy. I think I know why, but a some discussion on why this occurs would be helpful. The real problem is that when running the executable the child classes see the path of its parent has changed (i.e. in the executable) and is broken.

    Are you *sure* that the break is merely because the *path* to the parent has changed? The RTE generally doesn't care about that. Usually it requires that the substance of the dependency have changed to cause a break. Just a guess, but I suspect that the version numbers are being changed. That's what this *feels* like. It would help if you posted the exact text of the error you're seeing.

    (closing eyes, imagining setup... all of the following is speculative)

    Let's see... you have a parent class that is built into an EXE and a child class that is going to be dynamically loaded into that EXE but which is not built as part of the EXE.

    1. The child is actually produced through its own Source Distribution build (I presume that's what you mean by "when saving child classes with all dependencies"). A copy of the parent class ends up sitting next to the child because the child depends upon the parent class. See #4 for further thoughts about this copy.
    2. The EXE runs and tries to dynamically load the child. I assume you've worked out the path issues to successfully point to a file not inside the EXE (otherwise you wouldn't be getting the kind of error that you describe).
    3. The child was saved thinking its parent is at path XYZ. When it loads into the EXE, it finds that its parent is at path PDQ. That should be fine... as long as the parent classes are identical.
    4. Tangent: In fact, after the source distribution is built for the child, you should be able to safely delete the unneeded copy of the parent class. You only need that laying around if you are going to be loading the child someplace where the parent doesn't already exist. Now, back to the loading problem...
    5. The load should work if the two parents are identical. What could cause the two parent classes to not be identical? Well... how about if you built the EXE with "strip typedefs" but when you built the source distribution you did not "strip typedefs"? If the parent class had a typedef inside of it, it would now have different type (and thus a different version number). Hm... no, that shouldn't be the problem, because the parent in memory would have a future version number and a future version number should be fine... of course, that's assuming I've written the C++ code for loading in a run-time engine correctly, so this is worth checking.
    6. Ah, but if we reverse the equation, then there's a problem: If you did NOT strip typedefs when building the EXE but you DID strip typedefs when building the source distribution. Then the child class would be saved pointing to a parent whose version number had been bumped forward but the parent class in memory in the EXE would not be bumped, so the child class would complain about being unable to load with an old parent (because there is no way to unflatten data to older versions of the class, only newer ones). Ok, so this is worth testing: are the source distribution and the EXE both being built with the same "strip typedefs" settings?
    7. Assuming that isn't the problem, look through your EXE build specification for anything else that could cause a change to the parent class. Note, this isn't a change to the parent class' member VIs... for the version bump break, we're only looking for things that could change the .lvclass file itself (which includes the private data control, thus the typedef possibility).
    8. Having said that... does your parent class include any polymorphic VIs? Those get stripped by default when you build an EXE and are not stripped by default when you build a source distribution. I do not know enough about poly VI behaviors -- I pretty much never use that feature of LV -- so the following might be completely off base, but suppose that some member VI of the child class used the poly VI from the parent class. The parent in the EXE no longer has such a subVI. Does the polyVI node from the child's member VI cause the child's VI to break when the poly VI is missing? Or is LV smart enough in the RTE to ignore all references to polyVIs since those don't exist? I don't know. Perhaps someone on the forums knows?
    9. I can't think of anything else...

    That's all I can come up with from the data provided. Try the strip typedefs idea. If that doesn't work, post more details of the problem and maybe I'll think of something else.

  2. Err... when did this behavior change? 8.6 loads all library VIs and I thought 2009 does as well. Unless I'm not fully understanding what you mean by "load."

    Libraries have never loaded their VIs in the entire time since they were introduced in LV 8.0. Classes always have since they were introduced in LV 8.2.

    Open a .lvlib file. Yes, you'll see a list of VIs in the project tree but those VIs are not in memory, as you can see by looking at the VI Hierarchy window and choosing Show All VIs.

    Open a .lvclass file. Again, you'll see a list of VIs in the project tree, but this time, when you look at the VI Hierarchy window, you'll see all those VIs are actually in memory.

  3. I can see the problems you're having, but I am slightly unclear on exactly what your goal is, so I'll lay out a couple of options and hope one of them helps.

    You have some VIs that you want to invoke dynamically.

    1) If you're trying to get those VIs to load into memory at the same time as your top-level VI, what you want is a "static VI reference". [Note: "static VI reference" and "strict VI reference" are not the same thing, and, yes, it is possible to have a "strict static VI reference".] It's in the Application palette. This creates a reference to a subVI but does not invoke the subVI. You can then use the reference that comes out of that node and wire it to either the Call By Reference node or the Run VI method. If you *know* that you're going to want to run these VIs as part of your app but you just need to choose among them dynamically as the app runs, you will find it is most efficient to make these static VI references be "strict" by popping up on them and choosing "Strictly Typed VI Reference". That causes the subVI to be reserved for run when the top level VI starts running, the same way all the usual subVIs get reserved. Not doing this means that the subVIs will be reserved before every run and unreserved when the run finishes. Being strict also means that you cannot use the "Run VI" method. Being strict means that the VIs are set up to run as subVIs of another app. The Run VI method executes a VI as a top-level VI.

    2) The objection you might have to item #1 is that the subVIs will all load into memory. If you truly want to dynamically load these VIs into memory then you have to use Open VI Reference and supply a path. The easiest way is to put all of your dynamic subVIs in the same directory as the caller VI and then use "This VI's Path" node to get the path of the caller VI, then do "Strip Path" and "Build Path" to replace the file name of the caller VI with the file name of the desired dynamic subVI. From there you can again use Call By Reference or Run VI. Again, if you wire a conpane to the Open VI Reference node, the resulting reference is a strict VI reference which means you have to use Call By Reference to invoke it.

    • Like 1
  4. Or is a wire in effect the variable on the block diagram?
    Exactly. For a "variable" to be thread safe, we have to know all the places that are going to use it. We (LV R&D) could create a named thingamajig that is usable only on the current diagram, and only allows a single writer but many readers, and thus get knowledge of all the places it is used, but the representation that is most effective for saying "this data, generated here, is used there, there, and there" is a wire which visually shows all its branches. The "local variable" is for communication back to the front panel.
    The Clean-up-selection is useful for some areas, but there are some tweaks I then want to make. Once I have a section 'clean' is there any way to lock it? I see I can mark structures to "Exclude from diagram clean-up" but these are not structures, just sets of icons performing one function.
    Throw a "Sequence Structure" around the section and lock that structure. Remove these structures when you're done cleaning the diagram.
    Also, is there any way to change the color/look of a structure? I see that if you wire an error to a case structure you get red/green borders - it would be useful to do this sort of color-coding on other structures where I have error cases based on bools or variable values. It would also help distinguish the structure lines where I have cases within sequences within loops within sequences within cases.
    Yes. Use "View>>Tools Palette" to show the tools palette and then select the paint brush tool to paint the background of structure nodes. When you're done, click on the green LED to turn the autotool back on so you can continue doing selection, wiring, etc. There are some other specialized tools in that palette for other less common actions.
  5. LabVIEW 2009 has the "Clean Up Diagram" button -- shortcut key is ctrl+u. It is designed to help solve inherited code problems like the one you describe.

    Next newbie question - In some places there's a property node with miles of branching wires coming out to use the value in three or four different (faraway) places.

    My immediate temptation is to copy the property node to the places it is used, and just have really short single wires for each one. As long as this is within one sequence so there is no chance of the value changing between different instances of the property node, is there any overhead or issues associated with splitting it up this way?

    Or any stylistic reasons as to why one way is preferable to the other?

    You do create performance overhead with the copies of the nodes. Each property read makes a copy of the data in the property. For many properties, like "height" for example, this isn't a big deal. But if it is something like "Value" and the value is a large array, you might be duplicating a significant amount of data. Also, every property node has to switch to the UI thread where as computations can be done in the VI execution threads. The more times you go back to the UI thread, the less LV's compiler can help improve performance because all the parallelism is lost to serialization in the UI thread.

    In short, running a wire from the read of the property to all the places that need it is the most efficient and preferred solution. But if that diagram becomes completely unreadable as a result, sanity and code correctness are often worth more than a marginal performance improvement.

  6. Thank you for the helpful explanation. When the strictly typed reference was connected to a weakly typed sub VI, a red dot appeared at the connection. I interpreted this to be a class conflict, but perhaps the dot is there just to indicate that inputs will be "upclassed" as necessary, according to your explanation.

    That's a coercion dot. It's the same dot you see when you connect an integer wire to a double terminal. Just indicates that type is being converted automatically. It is sometimes important to be aware of them --- some can create performance problems or loss of precision or indicate a place where your type definition has been lost. But most of the time they're just informational. The coding conventions of LAVA require that you have an explicit cast for all type conversions and no coercion dots, but such a high bar standard is unnecessary in most day-to-day programming. If you're going to be producing a final product it's a fairly good practice.
  7. This is another bump from a guy who's currently trying to push an algorithm as fast as it will go. Looking for memory savings where possible. Did you ever finish the run through on queues AQ?

    No, and as much as I'd like to, I really don't see it happening. Writing ths requires a large block of unbroken time and it keeps getting trumped by other things.

  8. I've been running across this more frequently the last couple weeks. I suspect it has something to do with renaming/moving classes and methods, but I don't have a repro case.
    No known CARs on something like this.

    I'm going to be more than a bit distracted for the next couple weeks, so if you do get a repro case, post it to ni.com so an AE can percolate it up... I may not notice if you just post to LAVA.

  9. Did you modify the VI or did you overwrite the VI? If you modified the VI, it should work. If you overwrote the VI, the VI isn't going to think of itself as part of the library and thus will have the wrong qualified name and so when LV goes looking for a template by the fully qualified name, this one won't match. Is that possible?

    The only other scenario I can think of is that the file on disk is from a future version of LV that the current version cannot load -- happens to me all the time. :-)

    Other than those, your guess is as good as mine.

  10. If you are reporting a bug against LabVIEW (or any other product, for that matter) and you're using Windows 7, today I learned about a feature that might be helpful.

    Windows 7 includes a built-in mechanism for recording every mouse click/keystroke and screenshot that you do while recording. The feature is called the "Problem Steps Recorder."

    I was going to write about it, but I found this blog post online that walks through the details better than I could.

    http://www.istarteds...r-miracle-tool/

    If you've got a particularly hard to reproduce bug, rather than typing out all the steps to reproduce, and maybe forgetting something subtle but important, you can use the Problem Steps Recorder to create an mhtml file and submit that file as part of your bug report. That gives developers who evaluate your bug report an exact play-by-play of what you did and how the bug was created.

    Although probably overkill for most bug reports, I figure this might help some of the more complex situations.

    It's also useful for creating tutorials.

    • Like 1
  11. If you use an autopopulating folder anywhere then all the contents of that folder will be included in your project.

    If an item is in a library (class/statechart/xctl/plain library), the item will be listed under the library, even if it is part of an autopopulating folder.

    This can lead to the autopopulating folder saying an item cannot leave the project but the item isn't listed under the folder, so you don't recognize this fact, because the item is under its owning library.

  12. Seeing that bug in '09 has me a bit concerned that what I'm doing may be violating the rules of 8.6.

    The bug does not exist in LV 8.6. It was, as Norm guessed, introduced with the type propagation changes for data value references in LV 2009. The bug was hunted down and fixed for LV 2010 yesterday.

    I think I'm okay, but it never hurts to check... Is there anything wrong with typecasting a child class user event into a parent class user event, aside from the fact that it's possible for the event producer to send the wrong EventData child class along with the event?
    Short answer: Using the Type Cast node to change a refnum from one type to another is generally a bad idea. Rarely, it works, but more often LabVIEW beats you with an iron skillet and says, "No!"

    Long answer: I don't know. My guess is there's something bad about it, but that's just because of the short answer -- probability is not in your favor when you do this. In fact, after seeing it crop up in another user's code last week, I asked Darren N to add a test to the VI Analyzer suite to check for such typecasting and warn about it. You can play around with the casting and let everyone else know what is safe and what isn't.

    Assuming LV R&D has done its job correctly, there are exactly two situations that I know of where LabVIEW might crash and it's not a bug we can fix. The first is using a DLL node to call out to 3rd party code which does something abusive to the system. The second is using Type Cast on a refnum to a type that it isn't and then using that refnum. Some parts of the code have some guards to protect against this, but most don't for performance reasons (the compiler checks types, so having runtime checks just slows things down and the only reason for having the runtime checks is people using Type Cast to do things that can't ever work anyway).

    You might ask, if its such a problem, why Type Cast even works on refnums. Answer: because sometimes it is useful. The entire GOOP Toolkit was built by using such tricks. When we added the new queue API in LV 6.1, we maintained the old queue API by using Type Cast. Casting a refnum to an int32 makes a great database lookup key, and then you cast that int32 back to the original refnum to use it. You can use Type Cast to add/remove typedef to a refnum wire to eliminate a coercion dot. Then there's some really weird scripting tricks that work, like casting the refnum of a string constant to a string control in order to set bold face. But it is always a crap shoot. If you'll notice, the new data value references don't allow most types of casting with Type Cast. All the "legitimate" casts are taken care of by To More Specific and To More Generic. If you want to abuse a DVR, you have to cast to int32 first and then cast to another type.

    So go, play, see what you find, but check it out thoroughly before you use it in production code.

  13. So I have to ask: Why did you ignore it when I posted similar examples using USER events (see previous posts)? Is it because you don't see the same issue with user event references?
    I didn't notice what was going on. When I tried a couple of situations, they didn't allow the cast (notice, for example, it depends upon the order that wires are connected to the Build Array node whether it allows the bad behavior or not). I wasn't really delving into this whole thread because I expected the "you can't cast them" to kill the experiment. When it kept going, I thought, "That's strange, what did they find that I missed?" It wasn't until Norm explicitly called out what was happening that I realized what was up.
    What error do you think it will come up with? shifty.gif

    LV will likely crash. Eventually. If you're lucky, and only if you're lucky, you'll hit some emergency shutdown code that cleans up quickly. If you're unlucky, LV will do a lot of work messing up a lot of stuff before the problem gets detected or leads to a crash.

    Consider: If I can get parent data onto a child wire, then I can get a LabVIEW Object onto a child wire, which, since any class is a valid value of a LabVIEW Object, then I can get *any* class onto *any* wire (you can pretty quickly adapt my queue example of the bug to demonstrate this). The first time that that screwed up object goes to an Unbundle or Bundle node, LabVIEW will be indexing who-knows-what piece of memory and crash hard, or overwrite something important, or interpret the first four bytes of some string as a voltage, etc. etc. etc.

    Just answered my own question... I don't know if it's possible to get the "parent data on child" violation with a single event structure, but it's easily doable with two. Occurred to me right after my post.

    :-)

×
×
  • Create New...

Important Information

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