使用托管内存进行注册I / O RIOSend函数调用

时间:2013-02-06 14:32:36

标签: c# sockets c++-cli

我正在研究需要高速,低延迟/抖动通信的系统,并且用C#编写。我们看到有一种新机制可以通过名为Windows Registered IO http://www.serverframework.com/asynchronousevents/2011/10/windows-8-registered-io-networking-extensions.html

的套接字获得更好的性能

...但目前C#不可用......而且它肯定会在C ++测试中表现出更好的性能。

无论如何,我已经编写了Managed C ++ / CLI部分来创建一个DLL,这似乎可以很好地与C#一起工作并且数字有很大改进。

但我想知道我是否可以通过发送保存缓冲区副本......

目前C ++包装器如下所示:

bool ManagedSendData( array<byte> ^ buf, ULONG bufLen )
{
// must pin array memory until we're done with sending it, 
// at which point it'll be copied into the unmanaged memory

   pin_ptr<Byte> p = &buf[0];   // pinning one element of an array pins the whole array
   unsigned char * cp = p;

   return _RIObs->SendData( cp, bufLen );
}

其中_RIObs是实现已注册I / O功能的非托管C ++对象。在该函数中,它会将数据复制到使用RIORegisterBuffer()启动时注册的缓冲区中,然后调用RIOSend()以通知操作系统有数据要发送。

所以,我的问题是我可以让这个Managed C ++对象的用户在启动时传入一个托管字节数组,并在其上调用GCHandle::Alloc()来修复它并防止垃圾回收,调用{{1}托管应用程序中的它,然后在托管C ++对象存活时使用它?我将注册该托管缓冲区内存而不是非托管内存,当用户想要发送数据时,它们将填满他们已经引用的缓冲区,并通知我们要发送多少字节。它是阻塞发送并等待完成事件,所以他们不会再次使用缓冲区,直到操作系统完成了数据。

只要非托管应用程序可以互换使用托管或非托管内存,只要托管内存被锁定直到不再需要它,它就会起作用。

2 个答案:

答案 0 :(得分:2)

您可以直接从C#调用RIO,而不是通过C ++ / CLI;分配大缓冲区&gt; 85k将它移动到LoH而不是干扰常规GC,然后你可以使用类似于你的建议:

_underlyingBuffer = new byte[BufferLength];
var pinnedBuffer = GCHandle.Alloc(_underlyingBuffer, GCHandleType.Pinned);
var address = Marshal.UnsafeAddrOfPinnedArrayElement(_underlyingBuffer, 0);
var bufferId = _rio.RegisterBuffer(address, BufferLength);

我已经使用direct interop to Registered IOsome analysis将示例http回应服务器整合在一起(非常好)。

答案 1 :(得分:1)

这听起来像是一个很好的策略。只需确保在创建GCHandle时使用GCHandle :: Pinned以确保不移动内存。