C#方法相当于Java的DirectByteBuffer

时间:2013-07-20 21:50:00

标签: c# c++ marshalling bytebuffer

我正在学习如何在C#中使用C ++ DLL,并创建了一个c ++函数,它将两个已分配(Marshalled)变量集相乘。在C#和C ++中,一切都运行良好,直到我将分配的总大小从512MB增加到1024。然后visual C#给出了“受保护的内存访问冲突”的错误。这是dll函数,用浮点数填充缓冲区。限制必须介于512MB和1024MB之间。 Marshal.alloc只接受int大小的缓冲区长度,因此每个分配实际上有2GB的限制,但是当我尝试使用较小的块来超过限制时,会出现相同的错误。

问题:在C#中是否存在没有限制/限制的directbytebuffer等效项? 或者我正在做一些简单的指针错误?

dll和main项目都是64位目标,并且可以使用超过5-6 GB的内存和普通数组。

这是写入缓冲区的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);

测试任何硬件错误的RAM但通过了mem测试,因此必定存在软件问题。

感谢。

windows7-64位,cpu 64位,两个项目的目标机器64位。

1 个答案:

答案 0 :(得分:3)

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

这是代码中的一个严重错误,使用MSVC编译时, long 类型在64位模式下为32位。这不足以存储指针。它会偶然工作,直到你开始分配更大的内存块。 “av”的正确参数类型是指针类型,至少为void*。当然,没有理由避免仅仅声明它float*。如果你不试图欺骗编译器,代码总是更好。您必须在C#代码中将其声明为IntPtr。

你想要做的对齐是非常难以理解的。要求是SSE2代码的地址与16的倍数对齐。您可以使用此辅助方法:

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

还要向Marshal.AllocHGlobal()参数添加15(实际上8就足够了)。或者只是通过使用_aligned_malloc()和_aligned_free()从DLL中导出两个函数来处理这个问题。