5

我正在开发一个需要高速、低延迟/抖动通信的系统,它是用 C# 编写的。我们看到有一种新机制可以通过称为 Windows Registered IO 的套接字获得更好的性能http://www.serverframework.com/asynchronousevents/2011/10/windows-8-registered-io-networking-extensions.html

...但目前 C# 不可用 ...而且根据 C++ 中的测试,它肯定似乎显示出更好的性能。

无论如何,我已经编写了托管 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()以通知操作系统有数据要发送。

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

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

4

2 回答 2

3

您可以直接从 C# 调用 RIO,而不是通过 C++/CLI;分配一个大于 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);

我已经将一个示例 http echo 服务器放在一起,使用与注册 IO 的直接互操作并对其执行方式进行了一些分析(非常好)。

于 2015-07-26T09:52:21.067 回答
1

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

于 2013-10-30T05:13:22.247 回答