2013-07-20 55 views
0

我學習瞭如何在C#中使用C++ DLL,並製作了一個C++函數,用於乘以兩個分配的(Marshalled)變量集合。在C#和C++中一切正常,直到我將分配的總大小從512MB增加到1024。然後Visual C#給出「受保護的內存訪問衝突」的錯誤。這是dll函數,它使用浮動填充緩衝區。限制必須介於512MB和1024MB之間。 Marshal.alloc只接受int大小的緩衝區長度,所以每個分配實際上有2GB的限制,但是當我嘗試更小的塊來超過限制時,會給出相同的錯誤。相當於Java的DirectByteBuffer的C#方法

問題:在C#中是否有任何不受限制/限制的直接字節緩衝等價物? 還是我在做一些簡單的指針錯誤?

dll和主要項目都是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位,目標機器64bit,用於這兩個項目。

+0

那麼爲什麼你完全使用'Marshal.AllocHGlobal'呢?我不確定你爲什麼試圖做這個不安全的事情,你能詳細說明你究竟想要做些什麼嗎?結果應該如何,等等。 – aevitas

+0

@aevitas爲點積函數和矩陣乘法分配空間作爲大緩衝區。這比Parallel.For版本更快,速度比普通數組還要快(速度提高了6-7倍)。它在java上工作得很好,但是我試圖在C#中做同樣的事情。 –

+0

你是否在遇到OutOfMemoryException? – aevitas

回答

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

這是在代碼中一個嚴重的錯誤,該型是在64位模式32位時用MSVC編譯。這不足以存儲指針。它會意外地工作,直到你開始分配更大的內存塊。 「av」的正確參數類型是指針類型,至少爲void*。當然,沒有理由避免只是宣佈它float*。如果你不試圖愚弄編譯器,代碼總是會更好。您必須在您的C#代碼中將其聲明爲IntPtr。

你試圖做的對齊是相當難以理解的。要求是地址對齊爲SSE2代碼的16的倍數。您可以使用此helper方法:

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

同時添加15到Marshal.AllocHGlobal()的說法(8是足夠實際上)。或者簡單地使用_aligned_malloc()和_aligned_free()從您的DLL中導出兩個函數來處理這個問題。

+0

非常感謝,這解決了我的錯誤。在DLL中使用(void *)並在C#中使用IntPtr。我也試過malloc /免費包裝看它是如何工作,但malloc沒有分配(或它不顯示在Windows管理器)出於某種原因,但工作正常,自由工作也沒有任何警告罰款。 –