Exchange pinned array's pointer with an unmanaged memory pointer - c#

I'm pinning and unpinning with:
GCHandle pinArray(object a)
{
return GCHandle.Alloc(a, GCHandleType.Pinned);
}
void unpinArray(GCHandle h)
{
h.Free();
}
before and after an opencl method so array does not move while computing on it. Now I need to exchange backing array pointer with an aligned unmanaged array pointer to have faster read/write operations on it.
But I couldn't find anything like "change value of gchandle backing array pointer" info.
I need something like an "exchange" method:
GCHandle h=pinArray(array);
// how to?
IntPtr oldBackingArray=exchange(h,alignedMallocCSpace(10000000,4096));
// unmanaged operations
copyValues(h,oldBackingArray);
compute(array,...); // only passing with "array" for simplicity everywhere
array[3]=5;
l=array.toList();
compute(array,....);
Console.WriteLine(array[3]);
copyValues(oldBackingArray,h);
freeCSpace(exchange(h,oldBackingArray));
unpinArray(h);
does this need reflection to access and change that variable? There are also many C# methods using those arrays inside compute method so will it give more speed even on C# space too? So I'm tring to let C# to use alignedAlloc space for everything using "array" object until I unpin it.

You don't need to. The GCHandle relates to managed memory; unmanaged memory does not require any kind of GCHandle. Nor is it possible to talk to that memory as though it is a managed array. Instead, you need to accept that the unmanaged data is a pointer and only a pointer. You can abstract over the top of that to hide these details, but it doesn't change the reality. Fortunately, to the casual observer, talking to a SomeType[] is very similar to talking to a SomeType* - as long as you pass the lengths around yourself.
In the future, the upcoming Span<T> does a great job of unifying pointers and arrays, but that is only experimental at the moment.

Related

PInvoke: Allocate memory in C++ and free it in C#

We are using PInvoke to interop between C# and C++.
I have an interop struct as follows, with an identical layout C++ struct on the other side.
[StructLayout(LayoutKind.Sequential)]
public struct MeshDataStruct : IDisposable
{
public MeshDataStruct(double[] vertices, int[] triangles , int[] surfaces)
{
_vertex_count = vertices.Length / 3;
_vertices = Marshal.AllocHGlobal(_vertex_count*3*sizeof (double));
Marshal.Copy(vertices, 0, _vertices, _vertex_count);
}
// .. extract data methods to double[] etc.
private IntPtr _vertices;
private int _vertex_count;
public void Dispose()
{
if (_vertices != IntPtr.Zero)
{
Marshal.FreeHGlobal(_vertices);
_vertices = IntPtr.Zero;
}
}
}
Now I would like to add a second ctor
public MeshDataStruct(bool filled_in_by_native_codee)
{
_vertex_count = 0;
_vertices = IntPtr.Zero;
}
and then write a method in C++ that allows C++ to fill in the data. This would allow us to use the same structure for input as well as output data...
However, as far as I understand it, AllocHGlobal is available in C# and C++/Cli, but not pure C++.
So my question is: How can I allocate memory in C++ such that I can safely free it on the C# side with a call to Marshal.FreeHGlobal(...)?
This traditionally always ended up poorly, the Microsoft CRT created its own heap with HeapCreate() to service malloc/new calls in a C or C++ program. Can't deallocate such memory in C#, you don't have the heap handle.
That has changed however, starting with the CRT included with VS2012 (msvcr120.dll and up). It now uses the default process heap, the one returned by GetProcessHeap(). Also the one used by Marshal.Alloc/FreeHGlobal(). So you now have a shot at it, provided the native code doesn't use the debug allocator (crtdbg.h). Be careful throwing away that debug option.
The pinvoke marshaller was not changed, nor can it. If it has to release memory, like an array or string returned as a function return value, then it will call CoTaskMemFree(). It is not clear from your question which could apply. In case of doubt and if you have the choice in your native code then you can't go wrong with CoTaskMemAlloc(), paired to Marshal.FreeCoTaskMem() in your C# code.
From the documentation:
AllocHGlobal is one of two memory allocation methods in the Marshal
class. (Marshal.AllocCoTaskMem is the other.) This method exposes the
Win32 LocalAlloc function from Kernel32.dll.
When AllocHGlobal calls LocalAlloc, it passes a LMEM_FIXED flag, which
causes the allocated memory to be locked in place. Also, the allocated
memory is not zero-filled.
So, you can call LocalAlloc from your unmanaged code to allocate memory, and Marshal.FreeHGlobal from your managed code to deallocate it. Likewise, LocalFree can be be used in unmanaged code to deallocate memory allocated with Marshal.AllocHGlobal.
As the documentation also intimates, you could do the same with CoTaskMemAlloc/CoTaskMemFree and Marshal.AllocCoTaskMem/FreeCoTaskMem.
Having said that, you are setting yourself up for a fall doing it this way. It is far cleaner to keep the allocation and deallocation in the same modules. Mixing an matching in this way is very likely to lead to great confusion over who is responsible for deallocating the memory.

How do I get a byte* for the bits in a BitArray?

I am working on a C++ CLI wrapper of a C API. One function in the C API expected data in the form:
void setData(byte* dataPtr, int offset, int length);
void getData(byte* buffer, int offset, int length);
For the C++ CLI it was suggested that we use a System.Collections.BitArray (Yes the individual Bits have meaning). A BitArray can be constructed from an array of bytes and copied to one:
array<System::Byte>^ bytes = gcnew array<System::Byte>(40);
System::Collections::BitArray^ ba = gcnew System::Collections::BitArray(bytes);
int length = ((ba->Length - 1)/8) +1;
array<System::Byte>^ newBytes = gcnew array<System::Byte>(length);
ba->CopyTo(newBytes, 0);
pin_ptr<unsigned char> rawDataPtr = &buffer[0];
My concern is the last line. Is it valid to get a pointer from the array in this way? Is there a better alternative in C# for working with arbitrary bits? Remember the individual bits have meaning.
Is it valid to get a pointer from the array in this way?
Yes, that's valid. The pin_ptr<> helper class calls GCHandle.Alloc() under the hood, asking for GCHandleType.Pinned. So the pointer is stable and can be passed to unmanaged code without fear that the garbage collector is going to move the array and make the pointer invalid.
A very important detail is missing from the question however. The reason that pin_ptr<> exists instead of just letting you use GCHandle directly is exactly when the GCHandle.Free() method will be called. You don't do this explicitly, pin_ptr<> does it for you, it uses the standard C++ RAII pattern. In other words, the Free() method is automatically called, it happens when the variable goes out of scope. Which gets the C++ compiler to emit the destructor call, it in turns calls Free().
This will go very, very wrong when the C function stores the passed dataPtr and uses it later. Later being the problem, the array won't be pinned anymore and can now exist at an arbitrary address. Major data corruption, very hard to diagnose. The getData() function strongly suggests that is fact the case. This is not good.
You will need to fix this, using GCHandle::Alloc() yourself to pin the array permanently is very painful to garbage collector, a rock in the road that won't budge and has a long-lasting effect on the efficiency of the program. Instead you should copy the managed array to stable memory that you allocate with, say, malloc() or Marshal::AllocHGlobal(). That's unmanaged memory, it will never move. Marshal::Copy() is a simple way to copy it.

How to know pointer to structure by it's array pointer?

I have structure:
public struct MyStruct
{
public int a;
public int b;
public byte[] mass;
}
I need:
Pass poiner to "mass" array to C++ unmanaged function.
And after it done all work it will return me pointer to "mass".
So I have the list of MyStruct. And I need to know what the MyStruct in the list contains returned "mass"(wich pointer to I have).
If I know pointer to "mass" can I reduce pointer to 8 bytes and take pointer to MyStruct?
HOW TO :
1.Get IntPtr to "mass" array?
2.Get IntPtr to MyStruct structure?
3.Get MyStruct from IntPtr?
But, do not using any copy procedure, like Marshal.Copy...
Or is there a better way to do what I need ? Can I use pointers like in C++ or IntPtr is enought, and how can I do that?
Assuming that the memory for the array is allocated by the managed code:
When you pass an array to an unmanaged function via P/Invoke, then by default the array is generally pinned in memory by the marshaller so that the memory used by the array does not have to be copied.
You should not need to use an IntPtr at all - you just need to declare the P/Invoke so that it is accepting an array parameter.
However, things are different if the unmanaged code is allocating memory to be returned to the managed code; then things get MUCH more difficult.
Assuming that's not the case, then if you can show us the "C" function declaration we might be able to come up with a P/Invoke declaration.
(I do have a feeling that your situation may be a bit more complicated though...)
Some useful links for you:
http://msdn.microsoft.com/en-us/library/z6cfh6e6%28v=vs.80%29.aspx
http://msdn.microsoft.com/en-us/library/zah6xy75.aspx
How can I pass a pointer to an array using p/invoke in C#?
And some lower level information about the optimizations that the marshaller makes when calling unmanaged code and passing arrays. Essentially, if it can it doesn't make a copy of the data at all:
http://msdn.microsoft.com/en-us/library/23acw07k%28v=vs.80%29.aspx
Take care as the structure may have some specific memory alignment.
You may be interested by this link

Can IntPtr be cast into a byte array without doing a Marshal.Copy?

I want to get data from an IntPtr pointer into a byte array. I can use the following code to do it:
IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
But the above code forces a copy operation from IntPtr into the byte array. It is not a good solution when the data in question is large.
Is there any way to cast an IntPtr to a byte array? For example, would the following work:
byte[] b = (byte[])intPtr
This would eliminate the need for the copy operation.
Also: how can we determine the length of data pointed to by IntPtr?
As others have mentioned, there is no way you can store the data in a managed byte[] without copying (with the current structure you've provided*). However, if you don't actually need it to be in a managed buffer, you can use unsafe operations to work directly with the unmanaged memory. It really depends what you need to do with it.
All byte[] and other reference types are managed by the CLR Garbage Collector, and this is what is responsible for allocation of memory and deallocation when it is no longer used. The memory pointed to by the return of GetBuffer is a block of unmanaged memory allocated by the C++ code and (memory layout / implementation details aside) is essentially completely separate to your GC managed memory. Therefore, if you want to use a GC managed CLR type (byte[]) to contain all the data currently held within your unmanaged memory pointed to by your IntPtr, it needs to be moved (copied) into memory that the GC knows about. This can be done by Marshal.Copy or by a custom method using unsafe code or pinvoke or what have you.
However, it depends what you want to do with it. You've mentioned it's video data. If you want to apply some transform or filter to the data, you can probably do it directly on the unmanaged buffer. If you want to save the buffer to disk, you can probably do it directly on the unmanaged buffer.
On the topic of length, there is no way to know the length of an unmanaged memory buffer unless the function that allocated the buffer also tells you what the length is. This can be done in lots of ways, as commenters have mentioned (first field of the structure, out paramtere on the method).
*Finally, if you have control of the C++ code it might be possible to modify it so that it is not responsible for allocating the buffer it writes the data to, and instead is provided with a pointer to a preallocated buffer. You could then create a managed byte[] in C#, preallocated to the size required by your C++ code, and use the GCHandle type to pin it and provide the pointer to your C++ code.
Try this:
byte* b = (byte*)intPtr;
Requires unsafe (in the function signature, block, or compiler flag /unsafe).
You can't have a managed array occupy unmanaged memory. You can either copy the unmanaged data one chunk at a time, and process each chunk, or create an UnmanagedArray class that takes an IntPtr and provides an indexer which will still use Marshal.Copy for accessing the data.
As #Vinod has pointed out, you can do this with unsafe code. This will allow you to access the memory directly, using C-like pointers. However, you will need to marshal the data into managed memory before you call any unsafe .NET method, so you're pretty much limited to your own C-like code. I don't think you should bother with this at all, just write the code in C++.
Check out this Code Project page for a solution to working with unmanaged arrays.

What is the overhead of the fixed statement when used on an unmanaged struct?

In particular, I'm thinking of a scenario like this:
unsafe struct Foo
{
public int Bar;
public Foo* GetMyAddr()
{
fixed (Foo* addr = &this)
return addr;
}
}
Assuming a Foo stored in unmanaged memory, I'm trying to figure out what is involved in evaluating the fixed statement in GetMyAddr. I know as the programmer that this struct is never on the managed heap, I just need to get it's address in unmanaged memory in the most efficient manner. I'm especially concerned if there's any locking or atomic operations used here as that would make it completely unsuitable.
This won't do what you think it will do. The "fixed" statement only pins the managed object (this) for the duration of the "fixed" statement itself, which ends as soon as you "return". See the MSDN docs for the details.
You already say your "Foo" is in unmanaged memory, which means that the managed GC isn't going to be moving it around on you. In that case, can't you just return "&this" directly? Alternatively, you may want to consider taking your unmanaged object and marshalling it into a managed one. Give a little more context around what you're doing and we'll all be able to give more specific advice.
The expression &this has no meaning when the structure is present in unmanaged memory. There is no way to allocate it there. A key property of managed structures is that their memory layout is not discoverable and is not compatible with the unmanaged view of that structure. The CLR rearranges fields as it sees fit to get the minimum size while aligning members. It will in fact swap fields if a later one can fit in the padding.
You cannot get past Marshal.PtrToStructure to convert an unmanaged struct to its managed version. Marshal.SizeOf is only accurate for the unmanaged layout.
Basically there's no overhead at all. Fixed means "pin the location the pointer points to in memory, don't relocate it." Every other managed pointer can be "bent" by the Garbage Collector at will if it decides to move memory around. Fixed will prevent this, so basically it will "save" this (possible) overhead.
I don't know about the implementation of fixed pointers, but in the simplest case it's just blacklisting memory blocks. This is not very costly compared to normal managed pointers.
On the other hand, it prevents all sorts of optimazations that the GC might decide to perform in terms of memory management like increasing localization, reducing fragmenation etc.
I set up a micro benchmark and measured the overhead of fixed when used on a struct in unmanaged memory, it is very low, returning fixed(this) is only 10 times more expensive than simply returning this. That's acceptable for my use case (hashing using the address of the struct.) I was unable to learn how it was implemented, but it does seem to be fast enough in this case.

Categories

Resources