05-21-2019 12:20 PM
Hello All,
I have a small VI in which I output a value from an 'In Place Element Structure' through a tunnel. When running the VI, the wire within the structure has another value than outside of the structure.
I see this happen in LabVIEW 2015 (3 different LabVIEW installations) and in LabVIEW 2018.
Can others confirm what I see?
I would say this is a bug. Is it a known bug? I have not found anything in the known issue list.
If I change the code a bit, e.g. move 'Index Array' out of the structure, I get the correct value in the indicator.
05-21-2019 12:41 PM - edited 05-21-2019 12:43 PM
The in-place replace is occurring before the index array operation. Everything in the box(in-place structure) occurs in-place. It looks like it violates data flow, but I do not think that is the case.
You can get the answer you are looking for by moving the indicator inside the in-place structure, that way that operation occurs before the in-place swap.
mcduff
EDIT: The indicator is pointing to a memory location that is changed after the in-place swap.
05-21-2019 02:34 PM
Hello mcduff,
thank you for
@mcduff wrote:EDIT: The indicator is pointing to a memory location that is changed after the in-place swap.
I suppose the compiler is not making a copy of the array in this case. If I insert an 'Always Copy' node all is working as expected again.
I understand now what happens, but still I find it strange to see two different values on one wire.
05-21-2019 02:55 PM
@UliB wrote:
Hello mcduff,
thank you for
@mcduff wrote:EDIT: The indicator is pointing to a memory location that is changed after the in-place swap.
I suppose the compiler is not making a copy of the array in this case. If I insert an 'Always Copy' node all is working as expected again.
I understand now what happens, but still I find it strange to see two different values on one wire.
Interesting. You may want to put the always copy on the element that you indexed out, rather than the array. I'm not familiar enough with the inner workings of LabVIEW to know if it will actually copy the array, though.
05-21-2019 03:25 PM
@Mancho00 wrote:
Interesting. You may want to put the always copy on the element that you indexed out, rather than the array. I'm not familiar enough with the inner workings of LabVIEW to know if it will actually copy the array, though.
The 'Always Copy' works on the array wire and on the scalar wire.
If you branch the array wire before 'Index Array', connect it to the structure border and use it outside of the structure (force a copy), it is working in LabVIEW 2015, but not in LabVIEW 2018.
05-21-2019 03:52 PM
@UliB wrote:
The 'Always Copy' works on the array wire and on the scalar wire.
What I mean to say is, from a memory standpoint, you don't want to copy an entire array, just to index out one element, when you can do the index first, then do a copy of the single element.
@UliB wrote:
If you branch the array wire before 'Index Array', connect it to the structure border and use it outside of the structure (force a copy), it is working in LabVIEW 2015, but not in LabVIEW 2018.
I get the same (bad) result in 2017
05-21-2019 05:05 PM
My intution initially declared "bug". Further consideration makes me think "potentially surprising but not a bug."
Boiled down, I think it's just a less-commonly-seen race condition pattern. The in-place structure kinda promises to do all it can to reuse the same memory space. There are 2 chunks of parallel code that interact with the data in that memory space. One writes, the other reads, and there's no constraint to guarantee which one happens first.
-Kevin P
05-21-2019 05:19 PM
@Kevin_Price wrote:
My intution initially declared "bug". Further consideration makes me think "potentially surprising but not a bug."
Boiled down, I think it's just a less-commonly-seen race condition pattern. The in-place structure kinda promises to do all it can to reuse the same memory space. There are 2 chunks of parallel code that interact with the data in that memory space. One writes, the other reads, and there's no constraint to guarantee which one happens first.
-Kevin P
I do not think it is a race condition. Assume element 1 of the array has the memory address A. Inside the in-place structure before the element is rewritten, the wire reads memory address A; outside the in-place structure the indicator is tied to memory address A so it reads the new element.
Look the snippet below, it behaves as expected. Not sure why the OP did not use the following method to change an array element. I think the key is the OP is changing an array, not an element.
mcduff
05-21-2019 06:10 PM - edited 05-21-2019 06:14 PM
My understanding of the IPE structure is mostly ad-hoc so I'm open to correction. I haven't personally experienced a (known) race-condition-like symptom in my own usage, but I'm pretty sure I've never used the Array split/rejoin pair either.
That said, here's what I take (friendly) issue with, emphasis added by me:
Assume element 1 of the array has the memory address A. Inside the in-place structure before the element is rewritten, the wire reads memory address A;
On what basis can you say that the read *must* happen before the rewrite? How is it guaranteed by the rules of dataflow and whatever "contract" is implied by the special In-Place data access thingies that attach to the border? (Edit: here I'm referring specifically to the "read" action of the "Index Array" primitive inside the IPE. I'm *not* referring to the border element that "reads" the subarray as discussed immediately following.)
My expectation is that the 1st subarray must be read out of the left-side border element before it's re-written at the right-side border element. I'd be pretty confident that the IPE "contract" would have to guarantee *that* degree of sequencing, similar to the way left and right side shift registers behave. But I don't know a reason to count on any further guarantees.
This very small guarantee and no more would explain why your alternate construct could be counted on to have known, predictable sequencing. But back now to the original subarray construct.
The way I broke things down was to work from the outside in. The 1st subarray wire coming out of the left-side element and the one going into the right-side element are both referencing the same memory space A. They are presumably referencing it via pointer because the whole point of the IPE is to do everything possible *not* to copy data. So my mental model is that these subarray wires inside the IPE are pointers to memory rather than distinct instances holding the contents of that memory space.
So in my mental picture (which I'm kinda fleshing out on the fly as I write), I ask myself, "what are the contents of memory space A when the code in this particular part of the diagram is executing?". And as I trace the respective subarray wires, I reach an impasse. The "read from" wire gets indexed to a scalar at a certain location on the diagram. The 'rewrite into" wire gets populated with a value at a different point on the diagram. They both reference the same memory space A. And I see nothing to tell me which one happens first.
So I'm still seeing a race condition, though again, my mental model of the IPE is fairly ad-hoc.
Your further thoughts? (And hopefully someone knowledgeable from NI will weigh in too).
- Kevin P,
arguing to clarify and learn, not to win
05-21-2019 08:42 PM
I am guessing here, so take everything with a grain of salt.
Inside the IPE the compiler tries to do everything in place, that includes everything in the box. So look at the first post, the index array is inside the IPE, but the indicator is on the outside of the IPE. The index array does NOT return a value, it returns a memory location for the first element of the array. So when the OP probed the inside of the IPE, the element was not replaced and the memory address gave the original value, outside the IPE the same memory address gives the new value. When you move the indicator inside the IPE you are forcing the the compiler to give the value at that point in the execution before the replace takes place. How do I know the read takes place before the write, best guess rules in the compiler, always read before you rewrite.
Sorry, just guessing here. This is rolfk territory.
mcduff