ToyLab Posted January 19, 2017 Report Share Posted January 19, 2017 Hello everybody, I am trying to create a common task class in labview where I would like to substitude the task vi with a task vi of different moduls. So that it would be possible to start, stop, set cycle time ... for each derived class. Additionaly I only like to use reference, since the task should run whereas I use the functions to access its private data. For example I would run two modules classes which are derived from the task: a measurment device and a generator device. Each class task communicates with its device and saves the data information in its private members. With read functions I would like to access the data from wherever by knowing the reference without waiting for the task to end. The picture below shows the task frame. The task itself is the vi receiving the dereferenced class. Since dynamic dispatching is needed I ran into problems handing the reference directly to the task. Understandably this blocks all my functions during the active time of the task. My question would be if there is a method whereas I could hand the reference to the task and still be able to use dynamic dispatching; to only dereference when a member is written. I hope I could express my problem in understandable way, otherwise I try my best to answer question. Don't forget I am new to Labview and english Best regards Martin Quote Link to comment
Tim_S Posted January 19, 2017 Report Share Posted January 19, 2017 The data value reference (DVR) is a pointer to the data (in your case an object). Entering the in place element (IPE) structure using the data value read/write puts a lock on the reference to ensure no one else tries to modify the data. This blocks any other code from using the DVR. So the only way for other code to access the data is to write back to the DVR when leaving the IPE. The only way to use a DVR in the way you are trying is to only access it at the moment you need to, which is not what you are doing. There is a significant time-cost of locking/unlocking the DVR that can make this a very undesirable way to use it. There are other means to access singleton data in multiple locations. There are action engines, single element queues, global variables... All have their pluses and minuses. However, is keeping the data by-value needed for your application? The compiler is pretty good about optimizing code to reduce data copies (there are good articles on how to improve memory performance on NI's website). Quote Link to comment
smithd Posted January 20, 2017 Report Share Posted January 20, 2017 (edited) From your description, it doesn't sound like you want to do what you are doing. None of your code in the image has any labels so I can't really understand what bits are important. However, you said you have code chunks which talk to their device and generate data. I would argue that you just want to create N parallel loops and use a more dataflow-y communication mechanism to move data around (queues, events, notifiers, or channel wires). Any process which needs to get the measurement data can subscribe to the queue/notifier/event and receive its own copy of the data. If you decide you do want to use DVRs, I'd suggest one workaround being that you introduce DVRs within the class rather than around the class. That is, the private data you're setting could be a big DVR cluster and then your task can have finer grain control over when it accesses that data. If it turns out that task just needs to read a copy of the information, it needs to obtain the lock just long enough to copy the data out, and then it can release the lock. Finally, the property node syntax for data accessors does allow you to operate directly on a DVR, but the access is only as fine-grained as the data access method. Edited January 20, 2017 by smithd Quote Link to comment
Neil Pate Posted January 20, 2017 Report Share Posted January 20, 2017 15 hours ago, ToyLab said: Don't forget I am new to Labview I think you are trying to bite off more than you can chew here. DVRs, LVOOP and especially Dynamic dispatch is not really the first thing you want to learn on your LabVIEW journey. Quote Link to comment
ToyLab Posted January 20, 2017 Author Report Share Posted January 20, 2017 (edited) First thank you very much for all you effort. I attached a small sample project to clarify things. 16 hours ago, Tim_S said: The data value reference (DVR) is a pointer to the data (in your case an object). Entering the in place element (IPE) structure using the data value read/write puts a lock on the reference to ensure no one else tries to modify the data. This blocks any other code from using the DVR. So the only way for other code to access the data is to write back to the DVR when leaving the IPE. The only way to use a DVR in the way you are trying is to only access it at the moment you need to, which is not what you are doing. There is a significant time-cost of locking/unlocking the DVR that can make this a very undesirable way to use it. 3 hours ago, smithd said: I'd suggest one workaround being that you introduce DVRs within the class rather than around the class Yes and I am wondering how I can hand the reference into the derived tasks. It was not possible for me to dispatch the object reference dynamically. I do have a few other ideas reaching from creating a copy of the object to using a reference to reference construct, but both have other drawbacks and might not work. First I try to find out if the construct is somehow decent, before I spend more time to investigate further solutions. Maybe you could provide me with your expert opinions LVOOP_TaskSample.zip - usage of the Get and Set functions of ClassA and ClassC are not implemented (probably doesn't matter) Btw. in my first project I have used the messaging system (Clustered Queues with function/type and variant) of NI. Its hard to explain but I didn't like much - thats why I started with OOP. Edited January 20, 2017 by ToyLab Quote Link to comment
smithd Posted January 20, 2017 Report Share Posted January 20, 2017 (edited) 2 hours ago, ToyLab said: Yes and I am wondering how I can hand the reference into the derived tasks. It was not possible for me to dispatch the object reference dynamically. Btw. in my first project I have used the messaging system (Clustered Queues with function/type and variant) of NI. Its hard to explain but I didn't like much - thats why I started with OOP. If you went for the DVR-inside-class route, you'd need a 'create' and 'destroy' function. Create would initialize the references (and potentially call the parent 'create' method) while destroy would release the DVRs. You would pass the 'create'-d object into the task loop, where it could dispatch normally. Enum or string + variant is a reasonable way to implement a message system, but it doesn't work as well for just transferring data around. A better fit is using user-defined events, which let you subscribe to several different data types in a single structure. As a nice bonus, the producer of the data doesn't have to be aware of the existence of any consumer -- there could be 10, there could be 0, it doesn't know or care. As a downside, if you're doing difficult processing and nobody is listening to the result, thats kind of a waste of processing power. Edited January 20, 2017 by smithd Quote Link to comment
drjdpowell Posted January 20, 2017 Report Share Posted January 20, 2017 (edited) Quote It was not possible for me to dispatch the object reference dynamically. Try an Object in a Cluster for your DVR, rather than an Object directly. There are special issues around Objects in DVRs that are possibly causing your problems. Edited January 20, 2017 by drjdpowell Quote Link to comment
ToyLab Posted January 20, 2017 Author Report Share Posted January 20, 2017 (edited) Thanks again for your suggestions. To overlay the task.vi it seems that I need at least one dynamical dispatched input, so that if the base class task.vi is called, it knows witch Task.vi from the child class should be executed. I could use an extra input just to determin the correct child class and then find a method to take the correct DVR from the cluster and work with that. To avoid blocking, I would pull the task out of the in-place-element structure and feed the object to the task.vi in the dynamical dispatched input. However I would not use it but take the reference of the object holding all DVRs.... This makes it not realy intutive... but let me play around with it a little mybe I missunderstand your suggestions at the moment Edit: A secound problem might be the selection of the correct reference from the object holding all references ... Edited January 20, 2017 by ToyLab Quote Link to comment
drjdpowell Posted January 20, 2017 Report Share Posted January 20, 2017 This makes it not realy intutive... but let me play around with it a little mybe I missunderstand your suggestions at the moment Reread my suggestion about the cluster. Don’t do what you just suggested. Quote Link to comment
ToyLab Posted January 20, 2017 Author Report Share Posted January 20, 2017 While I was playing around with the references object, I could get it running with a small work around. I attached it in case you are interested. I am now thinking of using the reference cluster as global functional variable. Than all modules run for them self (without interaction) and the top level can easily access the parameters of the modules. LVOOP_TaskSample.zip Quote Link to comment
ToyLab Posted January 20, 2017 Author Report Share Posted January 20, 2017 14 minutes ago, drjdpowell said: Reread my suggestion about the cluster. Don’t do what you just suggested. OK will try that now. Quote Link to comment
UnlikelyNomad Posted July 16, 2017 Report Share Posted July 16, 2017 I may have gone a bit overboard with an example but this demonstrates several things: Call Asynchronous cannot use a polymorphic member reference. To get around this the TaskMgr class has a static member that takes in a Task Instance and can then call the polymorphic task while it runs asynchronously. The Start Task.vi demonstrates setting up the static vi reference properly to use the call async node. The base Task class (and TaskMgr) follow my by-reference design to allow parallel operations. The key note here is that the reference is contained within the class data, as opposed to a reference of the class itself, which allows polymorphism to work correctly. Two example tasks are provided: BgTask is implemented as a by-reference design and demonstrates reading its "progress" in a parallel loop. Note that it only dereferences the class data when it needs to update a value, instead of keeping the reference locked for the entire execution of the task. SlowTask is by-value, though the Task base class it inherits from is still by-reference for control signalling and status tracking. TaskMgr.zip TaskMgr.zip Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.