【问题标题】:How can I mix the Concurrency Runtime with .NET code?如何将并发运行时与 .NET 代码混合使用?
【发布时间】:2010-08-24 15:52:32
【问题描述】:

我一直在 C++ 静态库中使用 Concurrency Runtime,最近想在 C++/CLI 项目中使用这个库,以利用 Windows 窗体设计器并避免 MFC。不幸的是,并发运行时与 C++/CLI 中所需的 /clr 开关不兼容。我尝试在“#pragma unmanaged ... #pragma managed”指令中包围包含的使用并发运行时的头文件,但是虽然这对我过去的其他代码有用,但在这种情况下它似乎不起作用.我的意思是我得到了错误:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\concrt.h(27): fatal error C1189: #error :  ERROR: Concurrency Runtime is not supported when compiling /clr.

我不太擅长混合托管和非托管代码,因此可能存在我不知道的解决方法。但另一方面,也许这只是一种愚蠢的做法。如果不是因为我发现 MFC 非常复杂,而且表单设计器又好又简单,我只会做纯 C++。喜欢将两者混合使用,有什么建议吗?

【问题讨论】:

  • 请不要让我们猜测“不起作用”是什么意思。

标签: .net visual-studio visual-c++ concurrency c++-cli


【解决方案1】:

在 C++/CLI 中使用 ConcRT 在 concrt.h 中通过以下语句明确禁用,因为它不受官方支持...

#if defined(_M_CEE)
   #error ERROR: Concurrency Runtime is not supported when compiling /clr.
#endif

您可以按照上面的建议使用 PInvoke 来解决此问题,或者您也可以使用指向实现习惯用法的指针通过转发声明一个“pimpl”类并将对 concrt.h 的依赖项隐藏到本机 .cpp 文件来解决此问题然后您可以将其编译成一个库并与头文件链接。

例如在 .h 文件中:

//forward declaration
class PImpl;

class MyClass
{
  ....
  //forward declaration is sufficient because this is a pointer
  PImpl* m_pImpl;
}

例如在您的 .cpp 文件中,该文件编译为本机库:

  #include <ppl.h>
  class PImpl
  {
   //some concrt class
   Concurrency::task_group m_tasks;
  }

【讨论】:

  • 优秀。正是我正在寻找的那种东西。谢谢!
  • 欢迎您,您可以随时在论坛 msdn.com/concurrency 上询问团队(如果我当时没有看 stackoverflow,请 PM 我)。
  • 我一直在尝试公开 task_group 类的一种运行方法,但它使用了一个模板。 AFAIK 如果它使用模板,则必须声明整个函数,这意味着不可能隐藏 ppl.h 的使用。还是我错过了什么?
  • 在您的 p_impl 类上添加一个方法,该方法采用指向函数的指针或包装 run 的 std::function 对象。
  • 这个技巧可以从编译和构建的角度解决问题。我的问题是,应该我们这样做吗?由于文档指出并发运行时不能与 /clr 模块很好地混合,这是否会导致运行时问题,尽管我们已经欺骗了构建系统。
【解决方案2】:

您可以考虑编写一个托管 GUI,并让它调用(使用 PInvoke)一个非托管 DLL:如果您可以将并发运行时以及使用它的代码打包为 DLL。

【讨论】:

  • 好吧,如果我足够了解 P/Invoke,为了使用 C++ 库中的各种类,我必须做一些主要的工作来包装每个类(例如,blogs.msdn.com/b/vcblog/archive/2008/12/08/…)。或者有没有更简单的方法?它几乎与创建/维护 MFC 一样多。至少我知道一些MFC;我从未使用过 P/Invoke。
  • @Michael 我不知道你的应用程序是什么,但在最简单的情况下,DLL 只需要导出一个函数,称为DoAllTheWork() 或类似的东西。该函数通过 PInvoke 从 GUI 调用。该函数(在 DLL 中实现)将在其实现中使用并发运行时作为实现细节;它不需要向 GUI 公开所有并发运行时函数。
【解决方案3】:

我不确定您的并发需求有多详细,但 OpenMP 可以正常工作(即,您可以组合选项 /clr/openmp

array<MyModelResult^>^ model ....;
#pragma omp parallel for
for(int i=0;i<model->Length;i++) {
    model[i] = ComputeModelFor(i);
}

【讨论】:

    【解决方案4】:

    即使 C++/CLI 中的 ConcRT 被显式禁用,您也可以通过在 vcxproj 文件中将 CompileAsManaged 属性设置为 false 并将 PrecompildHeader 设置为 NotUsing 来使用 clr 支持编译您的项目并在同一个项目中包含一些本机类(I'已经用 VS2013 测试过):

    <ClCompile Include="NativeProcessWithThread.cpp">
      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
      </PrecompiledHeaderFile>
      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
      </PrecompiledHeaderOutputFile>
      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
      </PrecompiledHeaderFile>
      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
      </PrecompiledHeaderOutputFile>
    </ClCompile>
    

    然后您可以从托管的 C++ 代码中像这样实例化该类:

    NativeProcessWithThread nativeProcess = NativeProcessWithThread();
    

    【讨论】:

      【解决方案5】:

      在使用 CLR 将 C++ 链接到 C# 时,我遇到了同样的问题。 此问题是在直接引用 CLR 项目中包含的头文件(*.h)中的以下项目时引起的。

      #include <ppl.h>
      using namespace concurrency;
      

      由于 CLR 不支持并发,这会在 CLR 项目构建中产生错误。将这两行移至对应的 *.cpp 文件即可解决问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-20
        • 1970-01-01
        • 2020-11-30
        • 2015-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-03
        相关资源
        最近更新 更多