简体   繁体   中英

Fixing an array of array in C# (unsafe code)

I'm trying to come up with a solution as to how I can pass an array of arrays from C# into a native function. I already have a delegate to the function (Marshal.GetDelegateForFunctionPointer), but now I'm trying to pass a multidimensional array (or rather; an array of arrays) into it.

This code example works when the input has 2 sub-arrays, but I need to be able to handle any number of sub-arrays. What's the easiest way you can think of to do that? I'd prefer not to copy the data between arrays as this will be happening in a real-time loop (I'm communicating with an audio effect)

public void process(float[][] input)
{
    unsafe
    {
        // If I know how many sub-arrays I have I can just fix them like this... but I need to handle n-many arrays
        fixed (float* inp0 = input[0], inp1 = input[1] )
        {
            // Create the pointer array and put the pointers to input[0] and input[1] into it
            float*[] inputArray = new float*[2];
            inputArray[0] = inp0;
            inputArray[1] = inp1;
            fixed(float** inputPtr = inputArray)
            {
                // C function signature is someFuction(float** input, int numberOfChannels, int length)
                functionDelegate(inputPtr, 2, input[0].length);
            }
        }
    }
}

You can pin an object in place without using fixed by instead obtaining a pinned GCHandle to the object in question. Of course, it should go without saying that by doing so you take responsibility for ensuring that the pointer does not survive past the point where the object is unpinned . We call it "unsafe" code for a reason; you get to be responsible for safe memory management, not the runtime.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.aspx

It makes no sense trying to lock the array of references to the managed arrays.

The references values in there probably don't point to the adress of the first element, and even if they did, that would be an implementation detail. It could change from release to release.

Copying an array of pointers to a lot of data should not be that slow, especcially not when compared with the multimedia processing you are calling into.

If it is significant, allocate your data outside of the managed heap, then there is no pinning or copying. But more bookkeeping.

The easiest way I know is to use one dimension array. It reduce complexity, memory fragmentation and also will have better performance. I actually do so in my project. You can use manual indexing like array[i][j] = oneDimArray[i *n + j] and pass n as param to a function. And you will do only one fixing just like you done in your example:

public void process(float[] oneDimInput, int numberOfColumns)
{
    unsafe
    {
        fixed (float* inputPtr = &oneDimInput[0])
        {
                // C function signature is someFuction(
                // float* input, 
                // int number of columns in oneDimInput
                // int numberOfChannels, 
                // int length)
                functionDelegate(inputPtr, numberOfColumns, 2, oneDimInput[0].length);
        }
    }
}

Also I need to note, that two dimension arrays rarely used in high performance computation libraries as Intel MKL, Intel IPP and many others. Even BLAS and Lapack interfaces contain only one dimension arrays and emulate two dimension using aproach I've mentioned (for performance reasons).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM