调用本机代码的多线程托管应用程序
Posted
技术标签:
【中文标题】调用本机代码的多线程托管应用程序【英文标题】:Multi-threaded managed application that calls native code 【发布时间】:2015-05-20 10:34:47 【问题描述】:我有一个使用 ASP WebApi 的服务。每个 http 请求都会转换为需要进行一些数据操作(可能更改数据)的线程。 API 层是用 C# 编写的,数据操作是用 C++ 编写的。 C# 层调用本机库并提供指向某个托管缓冲区的指针。
几个问题:
如何确保没有比赛?在这种情况下,本机库中的std::mutex
是否足够? (托管线程是否映射到本机线程?它们会共享相同的std::mutex
吗?)
如何确保 GC 在本机库处理托管缓冲区时不会释放指向托管缓冲区的指针?
【问题讨论】:
你想做什么,到目前为止你做了什么?为什么要管理缓冲区? C# 和 C++ 端是否都会操作该缓冲区?缓冲区是每个请求的,还是共享的?缓冲区中有什么? @Luaan 我们正在尝试尽可能高效地处理大量数据。这就是我们决定用 C++ 处理它的原因。缓冲区是受管理的,因为我更喜欢尽可能多地使用 C#。只有 C++ 操作数据。缓冲区保存我们的应用程序发送给我们的遥测数据 好的...但这意味着当您从 C# 调用 C++ 互操作方法时,您只会使用缓冲区,对吧?所以你可以处理例如锁定在 C# 级别,对吗?如果您不将fixed
引用保留太久,它甚至可能使下面的 fixed
方法工作得很好。
【参考方案1】:
-
您需要共享 缓冲区吗?如果缓冲区只在一个线程上使用,您可以省去很多麻烦。托管线程不会 1:1 映射到本机线程,但我不确定这是否对您的方案有任何影响。
您需要修复缓冲区,并在本机代码有指向它的指针的整个过程中保持固定 - 释放是您最不必担心的问题,.NET 内存一直在移动。这是使用
fixed
块完成的。
修复托管内存:
byte[] theBuffer = new byte[256];
fixed (byte* ptr = &theBuffer[0])
// The pointer is now fixed - the GC is prohibited from moving the memory
TheNativeFunction(ptr);
// Unfixed again
但是,请注意,禁止 GC 移动内存可能会给您带来很多麻烦 - 例如,它可能会在高吞吐量服务器中完全阻止堆压缩。
如果您不需要在托管环境中使用内存,您可以简单地为任务分配非托管内存,例如使用Marshal.AllocHGlobal
。
【讨论】:
谢谢。 1. 不幸的是,这必须是一个共享缓冲区(我们内存不足,无法复制它 2. wrl::ComPtr 可以通过管理引用计数来帮助这里吗? @Shmoopy 我不明白它怎么可能。在 C# 中安全地处理内存引用和指针实际上非常容易——例如,您可以从SafeBuffer
类派生一个类型;它将为您提供对非托管内存的安全引用,您可以相对轻松地使用它。但是如果不了解您的整个场景,就很难说出更具体的内容。以上是关于调用本机代码的多线程托管应用程序的主要内容,如果未能解决你的问题,请参考以下文章
通过 Marshal.GetFunctionPointerForDelegate 从本机 (C++) 线程调用托管函数 (C#)
NodeJS:具有多线程的本机 C++ 模块(openmp)
在退出之前跟踪 - 并正确结束 - C# - C++/CLI - C++ Windows 窗体应用程序中的本机和托管线程