LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Error ring excluded in executable?

Ah, good point. I actually did check to see whether this happens without the error ring and it didn't, but that was probably because I took the error wire from the clear errors VI, which apparently does force some dependency. That's what you get when you only have a couple of minutes to do something. I figured the code was enough for NI to analyze the problem.


___________________
Try to take over the world!
0 Kudos
Message 11 of 25
(1,858 Views)

Indeed good point by Jeff. I fail to see though why you say it doesn't have to do with the error ring. As tst says (I did the same too) some other constant wires do enforce the dependency and so prevent the error from happening.

 

So imagine, the dependency is enforced when I use a simple error constant but not if I use an error string. Both are static data so the behavior should be the same. That is why I think that the bug is releated to the error ring.

 

Am I missing something?

 

Peter

0 Kudos
Message 12 of 25
(1,844 Views)

As I see it there are two problems that set up what you saw.  Improper code migration of the no error error chain, and the parallel DVR branch not throwing at least a warning.  Better to keep that DVR private in an AE or a class.


"Should be" isn't "Is" -Jay
0 Kudos
Message 13 of 25
(1,828 Views)

Hmm, what is the point of a DVR if it's not "branched"? Data a DVR points to is shared among all entities that hold a copy of the DVR.

 

Note that the bug we talk about renders a problem not only in case of destroying a DVR. Any two (concurrent) accesses to a DVR is a race condition. So if the destroy DVR VI in my example is replaced with another in-place reading/writing the DVR, then the race condition depends on whether or not I use an error ring.

 

Plese see my new example (LV14 code attached).

 

Is such a usage an antipattern? I don't think so.

 

error ring.png

0 Kudos
Message 14 of 25
(1,819 Views)

@Bokor wrote:

Hmm, what is the point of a DVR if it's not "branched"? Data a DVR points to is shared among all entities that hold a copy of the DVR.

 

Note that the bug we talk about renders a problem not only in case of destroying a DVR. Any two (concurrent) accesses to a DVR is a race condition. So if the destroy DVR VI in my example is replaced with another in-place reading/writing the DVR, then the race condition depends on whether or not I use an error ring.

 

Plese see my new example (LV14 code attached).

 

Is such a usage an antipattern? I don't think so.

 

error ring.png


I would suggest that this is an anti-pattern.  My preference would be to create and destroy the DVR for each IPE structure.  Branching DVRs only copies the refnum just like creating two DVRs.  The idea here is you will help prevent race conditions that access the data concurently Obviously, avoiding race conditions is something to avoid anyhow. Then lets think of what happens with non-fixed width datatypes!

 

Capture.PNG

Most likely the second IPE will cause the memory manager to reallocate the buffer's memory location (or more liklely through an out of memory error)  Imagine then what happens without data depencance between the IPEs ~~~~~~~Scary stuff.

 

 


"Should be" isn't "Is" -Jay
0 Kudos
Message 15 of 25
(1,808 Views)

Jeff, what I mean is intended data race, e.g., semaphores. How would you implement in LabVIEW a data structure that is shared among threads?

0 Kudos
Message 16 of 25
(1,803 Views)

Create the DVRs explicitly for each user rather than branch one reference.  Protect concurrent access via semaphore to prevent race conditions.


"Should be" isn't "Is" -Jay
0 Kudos
Message 17 of 25
(1,792 Views)

@JÞB wrote:

I would suggest that this is an anti-pattern.  My preference would be to create and destroy the DVR for each IPE structure.  Branching DVRs only copies the refnum just like creating two DVRs.  The idea here is you will help prevent race conditions that access the data concurently Obviously, avoiding race conditions is something to avoid anyhow. Then lets think of what happens with non-fixed width datatypes!

 

Most likely the second IPE will cause the memory manager to reallocate the buffer's memory location (or more liklely through an out of memory error)  Imagine then what happens without data depencance between the IPEs ~~~~~~~Scary stuff.


Sorry, but WHAT?! I'm having trouble making sense of anything you've written here. The entire purpose of a DVR is to provide serialized access to a single piece of data from multiple locations. It's like a safer single-element queue (SEQ). Branching doesn't create 2 DVRs (and branching a queue wire doesn't create 2 queues). Whether the value is fixed-size or not is irrelevant. As with a SEQ, where you can dequeue a string of one length and enqueue one of a different length, you can substitute a different length value into a DVR. The major difference versus a SEQ is that with a DVR, the dequeue-modify-enqueue is guaranteed to be atomic.

 

There's nothing scary at all about the situation you describe, and you absolutely won't get a memory error from it (or if you do, it's a bug).

Message 18 of 25
(1,786 Views)

One more thought about this. Splitting a DVR wire is definitely not an anti-pattern. One common use of a DVR is with a LabVIEW Object, where you want to call several different methods (which may modify data) on the same object in different locations. There isn't necessarily a race condition - the methods may work on different pieces of data within the object, so the resulting state of the object is the same regardless of the order in which the methods execute - but during method execution, the method needs exclusive access to the object (you can't have multiple methods modifying the same object concurrently). The DVR provides that locking. Only one IPE has access to the underlying data a time; all other IPEs that need access to the DVR will wait until it becomes available.

 

The only thing that's odd about your code here is that you could chain the DVR wire through the while loop and IPE, but you chose to route around it.

 

Jeff - let's say that the underlying data was actually an object that contains a string, and inside the IPE the code called an accessor that wrote a new string to the object. Would you still think that was "scary"? If not, what's the difference between that and a string as the wrapped data type, given that objects are by-value?

Message 19 of 25
(1,756 Views)

Nathan,  I actually trust the LabVIEW memory manager to properly dereference the DVR Data.  (and yes, it took me a while to trust it )  However, You run the risk of some other developer hacking on code over-there deciding to destroy the DVR you were depending on still existing.  There is not method to enforce the opener of the DVR is the Closer of the DVR except a style check. (and your own VIA Test)  One reason I tend to use them only as needed and for what nothing else can do.

 

With a Class, I probably would not use a DVR unless I wanted to take certain related actions in multiple IPEs with multiple DVR Accesses in each IPE (Deadlock prevention and auto serialization)  Example Do Foo1 on Bar1 and Foo2 on Bar2,  Doo Foo3 on Bar 3 and Foo1Prime on Bar1 Do Foo3 on Bar3 and Foo2Prime on Bar2.  Without the IPEs you can deadlock attempting to get exlusive access to both resources in three places.  The IPEs will grab them all or block untill they are all available.

 

in an example of 1 DVR and serial access defined I'd stick to wiring the IPE DVR output if I used a DVR.


"Should be" isn't "Is" -Jay
0 Kudos
Message 20 of 25
(1,740 Views)