C # метод, эквивалентный Java DirectByteBuffer

Я учусь, как использовать C ++ DLL в C # и сделал функцию c ++, которая умножает два распределенных (маршалловых) набора переменных. Все хорошо работает как в C #, так и в C ++, пока я не увеличу общий размер выделений до 1024 с 512 МБ. Затем Visual C # выдает ошибку «нарушения доступа к защищенной памяти». Источником этого является функция dll, которая заполняет буфер с помощью float. Предел должен быть между 512 МБ и 1024 МБ. Marshal.alloc допускает только длину буфера целого размера, поэтому на каждое выделение существует ограничение в 2 ГБ, но когда я пытаюсь использовать меньшие порции, чтобы преодолеть ограничение, выдает ту же ошибку.

Вопрос: Есть ли какой-нибудь прямой байтовый эквивалент, который не ограничен / ограничен в C #?
Или я делаю простую ошибку указателя?

И DLL, и основные проекты нацелены на 64 бита и могут использовать более 5-6 ГБ памяти с обычными массивами.

Вот функция c ++, которая пишет в буфер:

__declspec(dllexport) void floatOne(long av, int n)
{
float * vektor1=(float *)av;
_mm256_zeroall();
__m256 r0=_mm256_setr_ps(1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f);

for(int i=0;i<n;i+=8)
{

_mm256_store_ps(vektor1+i, r0);

}
_mm256_zeroall();
return;
}

Вот как это используется в C #:

public void one()
{
floatOne(bufferAdr.ToInt64() + offset, N);
// offset here is the properly aligned address to start usage
// N is private variable of vektor class (vector length)
}

Вот как происходит распределение:

 public vektor(int n /* number of elements*/, int a /* alignmentı*/)
{
N = n;
bufferAdr = Marshal.AllocHGlobal(4*n + 4*a);
//a-1 was enough but I put a*4 to be sure it doesnt overflow.
offset = (a - bufferAdr.ToInt64() % a);
}

Вот импорт DLL:

[DllImport("cpuKullanim.dll", EntryPoint = "floatOne")]
public static extern void floatOne(long adres1, int n);

Проверено ОЗУ на наличие каких-либо аппаратных ошибок, но пройдены мем-тесты, поэтому должна быть программная проблема.

Благодарю.

Windows7-64 бит, процессор 64 бит, целевой компьютер 64 бит для обоих проектов.

0

Решение

  __declspec(dllexport) void floatOne(long av, int n)

Это серьезная ошибка в вашем коде, долго Тип 32-битный в 64-битном режиме при компиляции с MSVC. Этого недостаточно для хранения указателя. Это будет работать случайно, пока вы не начнете выделять большие куски памяти. Правильный тип аргумента для «av» — это тип указателя, по крайней мере void*, Конечно, нет причин не объявлять это float*, Код всегда работает лучше, если вы не пытаетесь обмануть компилятор. Вы должны объявить его как IntPtr в своем коде C #.

То, что вы пытаетесь сделать с выравниванием, довольно непостижимо. Требование состоит в том, чтобы адрес был кратен 16 для кода SSE2. Вы можете использовать этот вспомогательный метод:

    static IntPtr AlignAddressForSSE2(IntPtr addr) {
return new IntPtr((addr.ToInt64() + 15) & unchecked((long)0xfffffffffffffff0L));
}

Также добавьте 15 к аргументу Marshal.AllocHGlobal () (на самом деле достаточно 8). Или просто экспортируйте две функции из вашей DLL, которые позаботятся об этом, используя _aligned_malloc () и _aligned_free ().

3

Другие решения

Других решений пока нет …