2014-04-23 15 views
12

Tôi muốn ghim một mảng các byte dài 10 megabyte để mã được quản lý và không được quản lý có thể hoạt động trên đó.Tôi làm cách nào để ghim một mảng byte?

Kịch bản của tôi là tôi có trình điều khiển không được quản lý đọc dữ liệu từ thiết bị và ghi nó vào mảng lớn và ứng dụng được quản lý chỉ đọc dữ liệu đó.

Something như thế này:

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

Tôi muốn ghim dataArray để GC không di chuyển nó.

Điều gì xảy ra khi tôi chạy ứng dụng, tôi nhận được một DataAbortApplication và sau khi đọc trên internet tôi phát hiện ra rằng tôi nên ghim số dataArray để tránh lỗi này.

Tôi nên làm gì?

+1

Check-out 'cái tuyên bố fixed' http://msdn.microsoft.com/en-us/library/f58wzh21.aspx – Tawnos

+0

có thể trùng lặp của http://stackoverflow.com/questions/13293133/pinning- mảng-of-net-đối tượng? – LB2

+0

@FabianBigler: bạn có nghĩa là tôi không thể chia sẻ mảng lớn giữa mã được quản lý và không được quản lý? – ShrShr

Trả lời

20

Có 2 cách để thực hiện việc này. Đầu tiên là sử dụng câu lệnh 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 
    } 
} 

Tuy nhiên, có vẻ như bạn muốn mảng được ghim trong một khoảng thời gian dài hơn. Bạn có thể sử dụng GCHandle s để thực hiện điều này:

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

Điều này sẽ hoạt động nếu mã được quản lý và không được quản lý nằm trong cùng một quy trình. Để chia sẻ quá trình chéo, bạn sẽ cần phải sử dụng một tệp ánh xạ bộ nhớ. –

3

Dưới đây là một lớp học mà có thể được sử dụng để ghim một mảng byte cho đến khi được xử lý. Tuy nhiên, có vẻ như tệp bộ nhớ được ánh xạ sẽ phù hợp hơn trong kịch bản của bạn.

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; 
     } 
    } 
} 
Các vấn đề liên quan