如何在.NET中使用x64 Interlocked操作来处理MemoryMappedFiles?

7

我需要在.NET中的MemoryMappedFile中使用Interlocked操作(CompareExchange,Increment等)来访问内存。

我找到了一个非常相似问题的答案。问题在于,在64位操作系统上,并没有从kernel32(或任何其他)dll导出Interlocked操作(请参见例如http://blog.kalmbachnet.de/?postid=46)。

是否有其他方法可以在64位.NET进程中调用Interlocked函数来处理一块内存?


1
我会尝试编写自己的C Dll,其中包含调用interlocked函数的导出函数,并从.NET中使用PInvoke。 - Alex F
@AlexFarber 很好的观点!我正想问这个问题:) 你是否知道我是否可以轻松找到编译器内在的Interlocked函数的ASM实现(例如http://msdn.microsoft.com/en-us/library/2ddez55b(v=vs.80).aspx)?这样我就不必自己重新发明ASM代码了。 - Jan
2
你不需要这样做,只需从本地 DLL 中调用所需的函数,编译器会完成其余工作。我的意思是,对于每个你需要的互锁函数,编写导出的 DLL 函数来调用 Interlocked 函数。 - Alex F
5
使用这种原子访问函数的目的是为了将其内联,从而减少最小化开销。一旦需要进行PInvoke调用,那么这个目标就完全丧失了,在避免使用命名同步对象方面也就没有任何意义了。 - Hans Passant
1
@HansPassant,就我的情况而言,我与数百个长值共享内存缓冲区。为了避免争用,我需要数百个同步对象(互斥锁等)。此外,我希望使用 Interlocked,因为它们会强制将新值推送到内存高速缓存线(而内存屏障没有明确的时序)-但是你是正确的,P/Invoke 可能完全破坏这种好处 :| - Jan
1个回答

1

请为自己编写一个小的C++/CLI辅助库,提供可由托管代码使用的交错操作。

我认为最快的Interop路径是公开一个托管类,该类在内部调用一个未管理的函数,该函数本身使用交错内部函数。这样,您甚至不必通过PInvoke。


不幸的是,这并不是真的 - C++/CLI 比抑制检查的 P/Invoke 更慢 - 例如在这里看到:http://www.codeproject.com/Articles/253444/PInvoke-Performance?msg=4551831#xx4551831xx 或者在这里:http://www.xinterop.com/index.php/2013/05/01/ccli-vs-pinvoke-performance-part-one/ 因此,P/Invoke 是正确的选择(不幸的是,每次调用仍会增加十几个指令)。 - Jan
第一篇文章似乎表明C++包装器更快。在第二篇文章中,C++包装器变得非常慢,以至于我开始怀疑。也许没有打开优化或者进行了额外的工作(事实上 - C++包装器仅通过一个中间类调用sqrt。为什么?)。在两篇文章中,基准测试时间非常短。有很多噪音。DateTime.Now也不是非常精确。通常,它以15ms的步长增加。他的测试范围在10-30ms之间。我不信任这两篇文章,也不会花时间进一步调查。 - usr
我同意你的发现。关键是,如果你想要最大速度,你需要抑制与托管<->本机转换相关的所有堆栈跟踪探测等。使用P/Invokes,您可以通过指定SuppressUnmanagedCodeSecurity属性来实现这一点。使用C++/CLI包装器,您默认获取所有这些检查,据我所知,您无法快捷地绕过它们。 - Jan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接