2014-04-23 22 views
12

Chcę przypiąć tablicę bajtów o rozmiarze 10 megabajtów, aby zarządzany i niezarządzany kod mógł na niej działać.Jak mogę przypiąć tablicę bajtów?

Mój scenariusz jest taki, że mam niezarządzanego sterownika, który odczytuje niektóre dane z urządzenia i zapisuje je do dużej tablicy, a zarządzana aplikacja odczytuje te dane.

coś takiego:

byte[] dataArray = new byte[10*1024*1024]; 

chcę przypiąć DataArray tak że GC nie przesuwa go.

Co się dzieje, kiedy po prostu uruchomię aplikację, otrzymuję aplikację DataAbortApplication i po przeczytaniu w Internecie dowiedziałem się, że powinienem przypiąć dataArray, aby uniknąć tego błędu.

Jak/co mam zrobić?

+1

Zapoznaj się z 'fixed' oświadczenie http://msdn.microsoft.com/en-us/library/f58wzh21.aspx – Tawnos

+0

Możliwy duplikat http://stackoverflow.com/questions/13293133/pinning- array-of-net-objects? – LB2

+0

@FabianBigler: masz na myśli, że nie mogę udostępnić dużej tablicy między kodem zarządzanym i niezarządzanym? – ShrShr

Odpowiedz

20

Można to zrobić na 2 sposoby. Pierwszym jest użycie oświadczenie fixed:

unsafe void UsingFixed() 
{ 
    var dataArray = new byte[10*1024*1024]; 
    fixed (byte* array = dataArray) 
    { 
     // array is pinned until the end of the 'fixed' block 
    } 
} 

jednak, że brzmi to jak chcesz tablicę przypięte przez dłuższy okres czasu. Można użyć GCHandle S do osiągnięcia tego celu:

void UsingGCHandles() 
{ 
    var dataArray = new byte[10*1024*1024]; 
    var handle = GCHandle.Alloc(dataArray, GCHandleType.Pinned); 

    // retrieve a raw pointer to pass to the native code: 
    IntPtr ptr = handle.ToIntPtr(); 

    // later, possibly in some other method: 
    handle.Free(); 
} 
+4

To będzie działać, jeśli kod zarządzany i niezarządzany jest w tym samym procesie. Aby udostępnić proces krzyżowy, trzeba użyć pliku odwzorowanego w pamięci. –

3

Oto klasy, które można stosować do styku tablicy bajtu, aż zostanie usunięte. Jednak wygląda na to, że plik odwzorowany w pamięci będzie bardziej odpowiedni w twoim scenariuszu.

public class PinnedBuffer : IDisposable 
{ 
    public GCHandle Handle { get; } 
    public byte[] Data { get; private set; } 

    public IntPtr Ptr 
    { 
     get 
     { 
      return Handle.AddrOfPinnedObject(); 
     } 
    } 

    public PinnedBuffer(byte[] bytes) 
    { 
     Data = bytes; 
     Handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      Handle.Free(); 
      Data = null; 
     } 
    } 
} 
Powiązane problemy