Исправление массива массива в C # (небезопасный код) - PullRequest
6 голосов
/ 14 ноября 2011

Я пытаюсь найти решение о том, как я могу передать массив массивов из C # в встроенную функцию.У меня уже есть делегат функции (Marshal.GetDelegateForFunctionPointer), но теперь я пытаюсь передать в него многомерный массив (точнее, массив массивов).

Этот пример кода работает, когда вводимеет 2 под-массива, но мне нужно иметь возможность обрабатывать любое количество под-массивов.Какой самый простой способ сделать это?Я предпочел бы не копировать данные между массивами, поскольку это будет происходить в цикле реального времени (я общаюсь с аудиоэффектом)

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);
            }
        }
    }
}

Ответы [ 3 ]

11 голосов
/ 15 ноября 2011

Вы можете закрепить объект на месте, не используя fixed, вместо этого получив прикрепленный GCHandle к рассматриваемому объекту. Конечно, само собой разумеется, что тем самым вы берете на себя ответственность за то, чтобы указатель не выжил после точки, в которой объект не закреплен . Мы называем это «небезопасным» кодом по причине; Вы отвечаете за безопасное управление памятью, а не за время выполнения.

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

0 голосов
/ 15 ноября 2011

Самый простой способ, который я знаю, это использовать один размерный массив. Это уменьшит сложность, фрагментацию памяти, а также будет иметь лучшую производительность. Я действительно делаю это в моем проекте. Вы можете использовать ручное индексирование, например array[i][j] = oneDimArray[i *n + j], и передать n в качестве параметра функции. И вы сделаете только одно исправление, как вы сделали в своем примере:

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);
        }
    }
}

Также необходимо отметить, что двумерные массивы редко используются в высокопроизводительных вычислительных библиотеках, таких как Intel MKL, Intel IPP и многих других. Даже интерфейсы BLAS и Lapack содержат только одномерные массивы и эмулируют два измерения, используя упомянутый мной подход (по соображениям производительности).

0 голосов
/ 15 ноября 2011

Нет смысла пытаться заблокировать массив ссылок на управляемые массивы.

Значения ссылок там, вероятно, не указывают на адрес первого элемента, и даже если бы они это сделали, это было бы деталью реализации. Это может измениться от выпуска к выпуску.

Копирование массива указателей на большое количество данных не должно быть таким медленным, особенно если сравнивать с обработкой мультимедиа, к которой вы обращаетесь.

Если это важно, разместите данные за пределами управляемой кучи, тогда закрепление или копирование не производится. Но больше бухгалтерии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...