c# - 如何将 C++ std::future 返回值适配为 C# System.Threading.Tasks.Task?

标签 c# c++ task-parallel-library pinvoke std-future

我正在包装一个要从 .NET 使用的 C++ 库。 C++ API 中有返回 std::future 的函数。我想让 .NET 代理类返回 System.Threading.Tasks.Task

我想在 C++ 端添加一个替代方法,除了方法参数之外,它还会接受一个函数指针。然后我可以启动一个新线程(例如使用 std::async)并等待 std::future::get。一旦 std::future::get 返回,我就可以调用传入的函数指针。在 C# 方面,我会将指针传递给将完成返回的任务的函数。像这样的东西:

Task CallCpp(int a, int b) {
  TaskCompletionSource<int> tcs;
  Action callback = () => tcs.SetResult(0);
  IntPtr callbackPtr = Marshal.GetFunctionPointerForDelegate(callback);
  CppMethod(callbackPtr, a, b);
  return tcs.Task;
}
[DllExport]
external void CppMethod(IntPtr callback, int a, int b);
void CppMethod(void (*callback)(), int a, int b) {
  std::future f = realmethod(a, b);
  std::async([&]{ f.get; callback(); });
}

std::future realmethod(int a, int b);

(是的,代码存在内存管理问题。尽管如此应该足以理解这个想法)

最佳答案

编码异步完成或失败是相对容易的部分。我个人会使用在 C# 中实现的 COM 接口(interface),标记为 [InterfaceType( ComInterfaceType.InterfaceIsIUnknown )],有 2 个方法,如 setCompleted()setFailed( HRESULT status ),并在我开始任务时传递它,但这是个人喜好问题。

问题是缺少C++多线程实现。

Boost 在这方面更好,它的 future 类有 then method that can be used在不阻塞线程的情况下传播状态。

目前,标准 C++ future 不提供任何可比性。我认为你运气不好。

如果您可以修改该 C++ 库,将 API 更改为更有意义的内容,即可以以非阻塞方式通知完成。


没有 COM,生命周期管理很复杂。在您启动异步任务之后但在它完成之前,C# 端的某个人需要保留该函数指针。这是一个可能的解决方案,请注意它如何使用 GCHandle 使回调比任务更有效:

[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
delegate void pfnTaskCallback( int hResult );

[DllImport( "my.dll" )]
static extern void launch( [MarshalAs( UnmanagedType.FunctionPtr )] pfnTaskCallback completed );

public static async Task runAsync()
{
    var tcs = new TaskCompletionSource<bool>();
    pfnTaskCallback pfn = delegate ( int hr )
    {
        if( hr >= 0 )   // SUCEEDED
            tcs.SetResult( true );
        else
            tcs.SetException( Marshal.GetExceptionForHR( hr ) );
    };
    var gch = GCHandle.Alloc( pfn, GCHandleType.Normal );

    try
    {
        launch( pfn );
        await tcs.Task;
    }
    finally
    {
        gch.Free();
    }
}

关于c# - 如何将 C++ std::future 返回值适配为 C# System.Threading.Tasks.Task?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56152684/

相关文章:

尝试在 win 10 中打开设备时,c++ CreateFile() 返回 1(无效函数)

c# - 为什么 Interlocked.Increment 在 Parallel.ForEach 循环中给出不正确的结果?

.net - 我对 async/await、它的工作原理及其优点的理解是否正确?

c# - 监控工具在 c# 中拆分 gui 和后端代码

c# - 如何使用自定义命名空间创建 SyndicationFeed

c# - 用openCv将轮廓填充为黑色

performance - 如何在 F# 中实现异步而不是并行

c# - 带有分组项目的 ListView - 通过组标题复选框选择所有组成员

c++ - cgal中的三角剖分面

c++ - boost::bind 隐式转换为 boost::function 或函数指针