混合模式进程与托管到非托管IPC

时间:2013-02-20 14:18:13

标签: c++ .net garbage-collection c++-cli ipc

我正在尝试为我正在进行的当前项目设计候选人。它的客户端接口基于公开方法和回调的WCF服务。请求一直路由到执行计算,操作等的C ++库(使用boost)。

当前方案基于WCF服务,通过IPC与单独的本机C ++进程进行通信。

为了使事情变得更简单一点,这里建议采用混合模式(即有一个.NET进程加载其中的本机C ++层,最有可能通过非常薄的C ++ /与它进行通信) CLI层)。主要关注的是垃圾收集或其他.NET方面是否会阻碍该过程中非托管C ++部分的性能。

我开始查找安全点和GC辅助方法的概念(例如KeepAlive()等),但我找不到关于此或基准的任何直接讨论。从我到目前为止的理解,其中一个安全点是如果一个线程正在执行无人值守的代码,在这种情况下,垃圾收集挂起任何线程(这是正确的吗?)来执行清理。 / p>

我想我的主要问题是在同一进程中运行这两种类型的代码而不是具有单独的进程时,本机方面存在性能问题。

2 个答案:

答案 0 :(得分:2)

如果您的线程从未执行任何托管代码,则在.NET垃圾回收期间不会冻结它。

如果使用托管代码的线程当前正在本机代码中运行,则垃圾回收器不会将其冻结,而是将该线程标记为在下一次到达托管代码时停止。但是,如果您正在考虑一个长时间不返回的本机调度循环,您可能会发现您正在阻止垃圾收集器(或者留下固定的东西导致GC和碎片缓慢)。所以我建议让你的线程在本机代码中执行完全纯粹的重要任务。

确保编译器没有为某些标准C ++代码静默生成MSIL(从而使其作为托管代码执行)有点棘手。但最后,您可以通过谨慎使用#pragma managed(push, off)来完成此任务。

答案 1 :(得分:1)

启动并运行混合模式应用程序非常容易,但要使其运行良好可能非常困难。

在选择该设计之前,我建议您仔细考虑 - 特别是关于如何对应用程序进行分层以及您对非托管对象的预期生命周期。从过去的经历中得到的一些想法:

  1. C ++对象的生命周期 - 按架构 在本地范围内简要使用C ++对象,然后立即处理它们。 听起来很明显,但值得一提的是,C ++对象是非托管资源,旨在用作非托管资源。通常他们期望确定性的创造和破坏 - 通常广泛使用RAII。从托管程序控制这可能非常尴尬。存在IDispose模式以尝试解决此问题。这对于短寿命对象很有效,但对于长寿命对象来说却相当繁琐且难以获得。特别是如果你开始使非托管对象成为托管类的成员而不是仅仅生活在函数范围内的东西,那么程序中的每个类都必须是IDisposable,突然管理编程变得比ummanaged编程更难。

  2. GC过于激进。 总是值得记住的是,当我们谈论超出范围的托管对象时,我们在IL编译器/运行时的眼中而不是您正在读取代码的语言。如果一个ummanaged对象作为成员和托管对象保留旨在删除它可能会变得复杂。如果您的处理模式从程序的顶部到底部不完整,GC可能会变得相当激进。比如说,您尝试编写一个托管类,在其终结器中删除非托管对象。假设您对托管对象执行的最后一项操作是访问非托管指针以调用方法。然后GC可以决定在非托管调用期间收集托管对象的好时机。突然,在方法调用中删除了非托管指针。

  3. GC不够激进。 如果您在地址限制内工作(例如,您需要32位版本),那么您需要记住GC保留内存,除非它认为它需要放手。它对这些想法的唯一输入是管理世界。如果非托管分配器需要空间,则没有与GC的连接。非托管分配可能会失败,原因很简单,因为GC没有收集超出范围的对象。有一个内存压力API,但它只对非常简单的设计真正可用/有用。

  4. 缓冲区复制。您还需要考虑在哪里分配任何大内存块。托管块可以固定为看起来像非托管块。只有在需要看起来像托管块的情况下才能复制非托管块。但是,什么时候这个大型托管块实际上会被释放?