Выделение асинхронного завершения или сбоя является относительно простой частью.Я бы лично использовал интерфейс COM, реализованный в C #, помеченный [InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
, с двумя методами, такими как setCompleted()
и setFailed( HRESULT status )
, и передавал его при запуске задачи, но это дело вкуса.
Проблема в том, что многопоточной реализации C ++ не хватает.
В этом отношении лучше Boost, у него future
класс имеет then
метод, который можно использовать для распространения состояния без блокировкиthread.
В настоящее время стандартные фьючерсы C ++ не предлагают ничего похожего.Я думаю, что вам не повезло.
Если вы можете изменить эту библиотеку 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();
}
}