如何将C std ::未来返回值调整到C#System.Threading.tasks.task



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

我想到在C 方面添加一种替换方法,该方法除了使用方法参数外还将采用功能指针。然后,我可以启动一个新线程(例如使用std::async(,并在std::future::get上等待。std::future::get返回后,我可以将传递的功能指针拨打。在c#侧,我将将A指针传递给可以完成返回任务的函数。类似:

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接口,标记为[InterfaceType( ComInterfaceType.InterfaceIsIUnknown )],并使用setCompleted()setFailed( HRESULT status )等2种方法,然后在我启动任务时通过它,但这是一个口味问题。

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

bubost在这方面更好,它的future类具有then方法,可用于传播状态而无需阻止线程。

目前,标准C 期货没有提供任何可比的东西。我认为你不幸。

如果您可以修改C 库,请将API更改为更有意义的事物,即可以以非阻滞方式通知完成。


没有com,终生管理很复杂。在启动异步任务但完成之前,C#Side上的某人需要保留该功能指针。这是一个可能的解决方案,请注意它如何使用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();
    }
}

相关内容

最新更新