10-19-2007
01:36 PM
- last edited on
05-05-2025
12:27 PM
by
Content Cleaner
I have lately been working with a Call Library Function Node that returns values through a void pointer pointer - not a pointer to an array, but a pointer to a pointer to an array. I have thus set up the CLN to treat this as a pointer to an unsigned 32-bit integer, and then use this integer as an input for MoveBlock, precisely as in this example.
This actually works pretty well - or at least, it appears to. Unfortunately, working with the program tends to cause LabVIEW to become very unstable, and it usually crashes soon after I run the program. I suspect memory corruption. (Using DSNewPtr and DSDisposePtr elsewhere in the code probably doesn't help much either.)
Is there something I can do to make using MoveBlock less temperamental? Maybe I can make a copy of the array and then use MoveBlock to put it back in its original location? Is there something relatively simple I could put into a Call Interface Node that would call the function and return a pointer instead of a pointer to a pointer?
10-19-2007 04:14 PM
10-19-2007
04:58 PM
- last edited on
05-05-2025
12:27 PM
by
Content Cleaner
Nope, passing an Array Handle (or an Array Handle Pointer) just causes LabVIEW to crash, regardless of whether or not I wire up a larger-than-necessary pre-allocated array.
Is this in fact not what I'm looking for? This article speaks ominously about "LabVIEW array handles", as if they're something different. Or is the problem that the data I'm looking for is actually pre-allocated by a different function?
Message Edited by kehander on 10-19-2007 05:00 PM
10-22-2007 10:15 AM
10-23-2007 12:36 AM
10-23-2007 01:38 AM - edited 10-23-2007 01:38 AM
@kehander wrote:
Oh, buckets... That's just an Array Handle Pointer, isn't it? Methinks I may proceed to pound my head vigorously.
First, MoveBlock in itself works absolutely perfect but only IF and only IF provided with the correct parameters. There are no belts and suspenders around that function, like LabVIEW does so conviniently in normal diagram code, so one byte of and trouble start.
Second: A LabVIEW handle is a pointer to a pointer but the opposite is absolutely not true. A LabVIEW array (or string) handle prepends the data area with a int32 that tells it how many array elements do follow. And LabVIEW being careful to never mess this value up, does expect you to do the same. So this int better represents the number of elements that follow (can be less than the handle was allocated space for, but never even one single byte to much)! To make matters even more "pointerless", the master pointer (the first pointer) simply points to the second one, but the memory allocated "knows" to which master pointer it was allocated. This is a LabVIEW specific implementation for its handles and messing with that will turn LabVIEW belly up at some point. So LabVIEW handles are never a good idea to be passed to other external C code, unlees this code has been designed specifically to use these datatypes and also makes proper use of the according LabVIEW memory manager functions (which makes that external code useless for non LabVIEW hosts).
Your problem most probably is not in the MoveBlock function itself if you have done it like in the example but in what you do on that pointer you get from the MoveBlock function. Somewhere someone has allocated that pointer with some space and if you are not careful to never access any memory outside of that space (even just reading can be already fatal, but writing will mess up things for sure) you get sooner or later a crash or worse corrupted VIs and if you then happen to safe them you may be never able to load them again.
You might also run into threading issues. You call a function and get that double pointer back, turn it into a pointer and do something on it but some other part of the library you called has already decided that the pointer is not necessary anymore and deallocates it. You must be very careful in dataflow dependency and make sure that the function that could cause deallocation, is never ever called before you are done with your pointer completely. This sometimes requires artifical datadependancy in the diagram to make sure that some operation has finished before the function that could deallocate (or even reallocate) that pointer.
Rolf Kalbermatter
Message Edited by rolfk on 10-23-2007 08:45 AM
10-23-2007 10:33 AM - edited 10-23-2007 10:33 AM
Message Edited by kehander on 10-23-2007 10:34 AM
10-31-2007 12:20 PM
@rolfk wrote:
Your problem most probably is not in the MoveBlock function itself if you have done it like in the example but in what you do on that pointer you get from the MoveBlock function. Somewhere someone has allocated that pointer with some space and if you are not careful to never access any memory outside of that space (even just reading can be already fatal, but writing will mess up things for sure) you get sooner or later a crash or worse corrupted VIs and if you then happen to safe them you may be never able to load them again.You might also run into threading issues. You call a function and get that double pointer back, turn it into a pointer and do something on it but some other part of the library you called has already decided that the pointer is not necessary anymore and deallocates it. You must be very careful in dataflow dependency and make sure that the function that could cause deallocation, is never ever called before you are done with your pointer completely. This sometimes requires artifical datadependancy in the diagram to make sure that some operation has finished before the function that could deallocate (or even reallocate) that pointer.
11-01-2007 03:03 AM - edited 11-01-2007 03:03 AM
There is absolutely no magic to MoveBlock. It is in fact just a memcpy() in disguise.
kehander wrote:Perhaps I am simply unclear on the precise functionality of MoveBlock.
The previously-mentioned example contains a pre-initialized array wired to the left "dst" terminal, the number of bytes in the pre-initialized array (four times the number of elements for a 32-bit integer) wired to the "size" terminal, and the memory address is passed to the "src" terminal as the Value of an unsigned 32-bit integer.So you have configured the dst array parameter as array data pointer, right? Not as array handle, pointer to an array handle or something like that?
MoveBlock is supposed to move the number of bytes starting from the address at the "src" terminal into the block of memory that held the pre-initialized array, right?Right!
Does this automatically de-allocate the memory that used to be at the old memory address?MoveBlock has no notice of the kind of buffers it is operating on and therefore no way of knowing how to deallocate them.
Would any other program be aware that the memory has moved?Nope! And it hasn't moved it just got copied over.
Is the data in the pre-initialized array simply overwritten, never to be seen again?Yes
What happens to the memory the next time the VI is run? Does LabVIEW try to re-use the same chunk of memory? Do I need to deallocate it first?As already said MoveBlock will not allocate nor deallocate any memory. The LabVIEW diagram that contains the Call Library Node however will!! You initialize an array (which allocates the memory for it) and pass it to the Call Library Node. Once the Call Library Node finishes execution the life time of that array will only be determined by how long a wire still goes through your diagram holding that array. If there is no wire coming out of the CLN or it stops at some point, LabVIEW will conclude that the array is not needed anymore and simply deallocate it at some point, but definitely before the loop or VI executes again. It could decide to reuse the memory for the next loop iteration for the same array initialization but there is no guarantee that it will, nor that the address in memory will be even remotely similar.
Why would deallocation of memory cause problems once the program has finished running, anyway?
Let's look at the previous point. You initialize an array and pass it to your DLL function as an array datapointer. Great! Now you do nothing with that array wire anymore and LabVIEW concludes: Hey that array is not needed anymore lets dispose it! Now your DLL goes and happens to try to copy data into the pointer it got previously and boom!! it overwrites some memory that now belongs to something entirely different. It may crash immediately but more likely it simply overwrites some data structures LabVIEW allocated to maintain some internal states and other information. Sooner or later LabVIEW will want to interpret this data again and walk into nirvana.
Theoretically LabVIEW could even reallocate the array in between loop iterations too and in that way it's address gets changed and your DLL then operates on an invalid address again. However LabVIEW uses DS handles for diagram data and they are guranteed to remain fixed in virtual memory address space as long as they are allocated, except when you happen to cause to resize them by inserting or appending elements to an array for instance.
But no matter what you do, once an array wire stops in the LabVIEW diagram or goes into a function that does a resize on that array the underlying memory location will be disposed of and eventually be reallocated, which will be almost always at a different location, so your first DLL function you passed that array pointer to simply will write into wrong memory.
Rolf Kalbermatter
Message Edited by rolfk on 11-01-2007 10:07 AM
01-21-2009 10:53 AM
I am doing the similar to kehander things currently, meaning that I am trying to read the CCD camera data from the buffer using CLN of the Labview. Partially, it works but my Labview makes some things I can not explain for now. May be somebody here had a similar problem or in general have an idea what can be wrong.
In C++ I created my dll that in turn uses the functions from the CCD camera library. The part of the code looks like that:
uns16 *frame; // Pointer to the requested image
uns32 size; //Size of the buffer
int dims[2]={512,512};
rgn_type region={0, 511,1,0,511,1};
_declspec(dllexport) int AcquireStabdard(………, uns16 ARRAY[]){
…
…
Pl_exp_setup_seq(hCam,1,1,®ion, TIMED_MODE, Exposure_Time,&size); // prepares camera to perform a readout
//&size pointer is filled with the number of bytes of memory needed to buffer the full sequence
Frame=(uns16*)malloc(size); //allocates memory buffer for data collection
Pl_exp_start_seq(hCam, frame); //we know the address in memory where our data are
Then we use Moveblock(frame, ARRAY, (size_t) size) OR memcpy(ARRAY, frame, (size_t) size) to copy our Data to the ARRAY defined in Labview
}
In Labview I used CLN. ARRAY defined as array pointer. I initialized ARRAY with the size, in this example, 512x512 (my camera region is 512x512).
Now are the QUESTIONS!
1.Why when I run my VI first time I don’t see the data and when I run VI the second time and following times (until it crashes) I see the data???
2.Why when I use the small region, i.e.
region={0, 99,1,0,99,1} all my ARRAY in Labview is filled with the data correctly and when
I use {0, 511,1,0,511,1}only the first rows I filled and the rest are NULLS what shouldn't be. It
looks leike the data was copied partially from the correct memory block and partially not.
Does anybody has any idea?