Jump to content

QueueYueue

Members
  • Content Count

    66
  • Joined

  • Days Won

    6

QueueYueue last won the day on October 9 2018

QueueYueue had the most liked content!

Community Reputation

38

1 Follower

About QueueYueue

  • Rank
    Very Active

LabVIEW Information

  • Version
    LabVIEW 2012
  • Since
    2007

Recent Profile Visitors

1,064 profile views
  1. Hey, Derek here. Stoked to see GPM came up. Couple of things I want to mention. The current GPM release is still a beta release. If you find bugs or want to request features, add them to the issue tracker. https://gitlab.com/mgi/gpm/gpm @ShaunR Theres a CLI and a GUI. The CLI will probably be used by CI setups, the GUI will be used by people. Eventually (though not currently) anything that you can do in one you can do in the other.(the "commands" that the CLI and GUI execute are just two different ways of executing the exact same business logic.) I know it needs to support distributing things like quickdrop plugins. I haven't quite decided how I'd like to do it, but I definitely realize it's something that's needed before a full on release. https://gitlab.com/mgi/gpm/gpm/issues/18 Yeah, @David_L I agree, +1 to the number of package managers sucks. Sorry :/ Back to the OP's topic: One of GPM's goals was to answer this question. If you have code that you want to give out for free, I think it should be trivially easy to do so. Using GPM, you just fill out the meta data, create an account on https://gpackage.io/ and then click publish. Once the command has finished executing you're good to go. It's published on the internet so anyone can download it. Someone who wants to use your code just needs to install it using GPM. If your code depends on other packages they'll be installed at the same time. It should be super easy (let me know if it's not!) Additionally, GPM package meta data has all of the fields needed to properly index your stuff and link back to your repo. This makes it easy for people to find your code, and contribute to it as needed. Happy to answer any more questions (or argue about design decisions =P)
  2. Use this snippet as your base if you need to do an arbitrary amount of cluster items. I can never remember how to do it, so I always crack open Ready Anything (from MGI's Read/Write anything) to see how we did it there.
  3. I've made some pretty cool changes to Monitored Actor that help expand it's capabilities. The main being the ability to override the UI. This lets you do cool things like create a web based actor monitor, or run the monitor window in the runtime environment. I also added Actor Labels to help you identify running actors. Check out our Monitored Actor 2.0 article for more info! If you're at NI week, be sure to checkout the presentation by Brandon Steele on Thursday (1:30 in room 16B). He'll be covering the Monitored Actor as well as some other tips for developers of large application (like MGI Solution Explorer, Class Method Browser and Actor Framework Message Maker)
  4. Good news, we've got a major update to the MGI Solution Explorer. You can now create custom solution items, which allows us to do cool thinks like create self extracting zip, or help deploy your solution. Check out our MGI Solution Explorer 2.0 article for more info! If you're at NI week, be sure to checkout the presentation by Brandon Steele on Thursday (1:30 in room 16B). He'll be covering the Solution Explorer as well as some other tips for developers of large application (like Monitored Actor, Class Method Browser and Actor Framework Message Maker)
  5. I gave a presentation at the America's CLA summit this year where I introduced the MGI Solution Explorer. Here's the link to the presentation information and some documentation (that will be expanded) for the tool. MGI Solution Explorer Info Feel free to post feedback here.
  6. I put together a series of articles while working on an AF 101 presentation for our local CLD summit. Check them out and let me know what you think or if you have any questions/improvements. Part 1 – The Background Part 2 – The Actor Part 3 – Launching and Communicating Part 4 – Being Productive With Actors Basic Walkthrough – Creating a Logger
  7. It's possible to use the path control to do what you want, but it's a little hack-ey. You end up making the path control transparent, then only making it visible when the mouse is outside the VI's front panel. See http://digital.ni.com/public.nsf/allkb/81D867F8C6A1376D86257347001BE936
  8. Helper loops are an essential part of any AF project. Helper loops do all of the heavy lifting of your actor, while messages are just the public interface for the actor. There are times when you can get away with just doing things in messages (like a file logger for example), but anything that's doing anything meaningful will probably need to happen in helper loops. The reason you don't create nested actors is because you need finer control of things like timing or execution order or whatever. With a helper loop you can make sure that the Idle message stops any PID messages, or that the PID checking happens every X ms or whatever.
  9. You definitely do not want to have you PID timing based on time delayed send or AF messages in general. Remember, a message is guaranteed to get there, but it's not guaranteed to be handled in any time. So if you have a "Check PID" message, but the "Log data" message gets in there before it, the log data will happen first, then the "Check PID" will happen as soon as it can after the logging is done. This could introduce a lot of jitter. Another design principal that you should follow when writing actors is that messages shouldn't take too long to execute. Obviously "long" is very subjective, but in general you shouldn't have a message for something like "Wait for pressure to build" since it probably takes a handful of seconds at minimum. This means that you Actor's thread is locked for that time. So you cant send it an abort message if needed, you cant stop the actor, etc. The easiest way to do long running tasks or time dependent tasks using the AF is to have helper loops. To do this you override actor core, and drop another loop on the block diagram. Now you need to create some communication mechanism (regular old Qs, notifiers, etc) to communicate between the message handler Q (which is what the Parent's actor core is) and your new helper loop. You'll probably store a copy of this reference in your private data so Messages can communicate with your helper loop. You're probably already done something similar to this when writing UI Actors. Your helper loops will probably look very similar to a traditional state machine. The only difference is this additional communication mechanism.
  10. I get what you're saying, and I think it is neither pre-alloc or shared re-entrancy. You want a hybrid. I think there would be a lot of design decisions to be made with what you're suggesting. I feel like this would end up with new clones being allocated when you didn't expect it, sometimes a new clone wouldn't get allocated when expected, etc. Rather than forcing us to learn there rules (it's already hard enough with two re-entrancy types) it's just not available. You can do this on your own however. You can make all of the somewhat-arbitrary design decisions on your own, just follow drjdpowell's advice from earlier: But i'm telling you, you're setting yourself up for confusion and memory leaks. I think my pattern is better.
  11. Zyl, You're close to understanding it correctly. Here's how I think about re-entrancy. Pre-allocate -> VI is allocated during compile time. Shared -> VI is allocated during run time. So..... Correct. I don't understand what you mean by this. Re-entrancy does concern the way you launch an execution AND how you manage the memory allocated with the previous launch. Shared clones are launched from a clone pool. So when execution needs a clone, it asks the clone pool for one. If there is one available, it gets it. If there isn't one available, the clone pool creates one for you. When you're done you return the clone to the pool. You have no control over which instance you get from the clone pool, it decides. This is why the uninitialized shift registers don't work as expected. You're expecting to get the same clone back every time, but the clone pool manager gives you back the first available clone. With pre-allocate you're linking to specific instance of the clone. There is no clone pool stuff because you're saying "I know I'll need this here so create it up during compile to save some execution time" So why can't you pre-allocate a dynamic dispatch VI? Because to pre-allocate you need to link to a specific instance of the VI right? To know the specific instance you need to know the runtime data type of the class coming in, which we don't know. To make pre-allocated work you'd need to allocate (at compile time) memory for every possible VI that could be called. This means that if you had a 2 child classes you'd need to allocate memory for 3 VIs (one for the parent and one for each child). Now what do you do if one of the child VIs calls the parent's implementation? maybe that should be allocated up front? Now what happens if you dynamically load a class in a plug in architecture? You're code would need to be recompiled to add the memory for that new class? See how we're running into all of these weird situations, all of which would required allocating a bunch more memory? Maybe it's possible, but it's not efficient, and it'd possibly introduce a whole slew of other complicated design decisions. So that's why you're not allowed to do it.
  12. You're in a race-condition. You get shared clones instantiated as needed. That means if you have two objects that both call the same VI, sometimes they'll get the first instantiation of the VI, sometimes they'll get the second. LV decides which. Take a look at the example it illustrates it. The VI who's ref you create is going to have a common connector pane across all classes. This means that if you have a child class, the input terminal will have to be of the parent's type. so you'll have to do a cast if you want to access any of the child's data. Either that or you'll have to use "Set control by name" invoke nodes, which I avoid at all costs. Attached is a 2012 version of my example. Pealloc Testing 2012.zip
  13. Ohh man, lots going on here. I made an example using references. Calling NI's VIs by ref is what I'm talking about. There's no difference in newer versions of LabVIEW. The reason you cannot call a dynamic dispatch VI by reference is because a reference points to one VI. Dynamic Dispatch, however, means you don't know what VI you're calling until runtime (and by runtime I mean right before the VI is called). What if you open a reference to Class A's Implementation of a method, then you wire Class B to the input? They both have the same connector pane. What if you open a reference to the parent's implementation, but then wire in a child? You need to call the Child's method, but you have a reference to the parent's. There's a bunch of situations where you'd be trying to call the wrong implementation on the wrong class, so that's why you get a broken run arrow. In response to the number of references: Who cares? Store all of the references inside the class data, and then give that class a "cleanup" method. Done. Opening a lot of references is no big deal as long as you close them. It'll work, but I'm pretty sure you'd have to do some casting to get the control panels to line up. See my posted example for a cleaner (IMO) implementation that's pretty similar to what you're suggesting. This has almost nothing to do with LVOOP. If you called a pre-allocated VI inside of a shared clones VI in any instance you'd have this problem. This is an advanced feature that needs some extra thought by the programmer. About the example: Open "Test VI.vi" and run it with "Call By Ref?" set to False and run the VI. Notice string 1 and string 2 are changing. They will flip flop based on which instance they happen to get (it's a race!) Stop the VI by clicking the stop button. Now set "Call By Ref?" to True and run the VI. String 1 and String 2 will now get their own values that stay the same. Take a look at the code, most of the magic happens in "Test Class.lvclass:Test VI.vi" (note: This is the re-entrant shared clones VI). On first call (for that object) it opens a new ref to the pre-allocated VI, and on subsequent calls it just uses the reference it already has open. Let me know if you have questions. Pealloc Testing.zip
  14. You're right. You can't use un-initialized shift registers like you want inside a shared clone VI. This does mean that if you put any of NI's VIs which use pre-allocated re-entrancy inside your shared clone VI you will be screwed. And since you're forced to use shared clones with Dynamic Dispatch VIs, you're double screwed. All and all, this means that data that needs to be stored between calls needs to be placed in the object's private data. It will now live on the shift register and the clone will just use the data, instead of storing the data. If you were writing the code from scratch, this would be no big deal, but since you're using NI's code, it becomes a pain. What I ended up doing is writing my own version of NI's VIs (typically started by coping and pasting) that strips out all of the shift registers. I think (I've not tested this way) you could also open a VI reference to the VI, then use a call by reference, and store the reference in the objects private data. I'd have to play around with this way though. It's annoying, and honestly, I think that NI should go back and give us a version of their VI's that don't have shift registers in them. Obviously this is a lot of work without much return, so I don't blame NI for not doing it. And that kids, is why you don't use globals unless you're 100% sure you need them and there's no other way.
  15. Two ways to do what the OP is asking. 1. VI Server world: Children have a static link to their parents and Parents have a dynamic link to their children. This means that once a class is loaded into memory, the parent knows about the child. According to the documentation this will NOT work in the runtime environment, but i've used this several times when making IDE Tools. 2. Runtime Reflection: The following code will also give you an array of all of the children loaded in memory, but this time it uses less VI Server so it will work in the runtime environment. I use this when using a plugin architecture. I've not done a lot of performance testing with it, but on a medium-ish size project (one with ~150 classes) it only takes about 50 ms to run, so it's worked well for me so far. Having given you those solutions, I still think your best bet is to use a statically defined array. This will ensure things are loaded into memory when their needed and such. My solutions really only become worth it once you're dynamically loading classes.
×
×
  • Create New...

Important Information

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