Asynchronous F#:从接受回调并返回取消句柄的函数创建异步
我对F#还不熟悉,并试图围绕C库编写包装器模块。C库有一个具有此签名的函数:Asynchronous F#:从接受回调并返回取消句柄的函数创建异步,asynchronous,f#,ffi,Asynchronous,F#,Ffi,我对F#还不熟悉,并试图围绕C库编写包装器模块。C库有一个具有此签名的函数: handle*call_callback(void(*callback)(int)); 它还有一个功能,允许通过使用手柄*取消上述功能: void cancel_回调(句柄*h); 我想将这对函数包装成一个Async 我熟悉Async.FromContinuations,如果不是因为需要调用cancel\u callback,我可以这样包装call\u callback: my_async=async.FromCo
handle*call_callback(void(*callback)(int));
它还有一个功能,允许通过使用手柄*
取消上述功能:
void cancel_回调(句柄*h);
我想将这对函数包装成一个Async
我熟悉Async.FromContinuations
,如果不是因为需要调用cancel\u callback
,我可以这样包装call\u callback
:
my_async=async.FromContinuations(乐趣(成功、错误、取消)->
let handle=call\u callback(成功)
)
这个问题是,我需要获得
handle
,并确保在取消此异步时调用cancel\u回调(handle)
。我找不到这样做的方法。有一个Async.OnCancel方法(),您可以等待它在取消任务时调用。或者,如果希望在成功、取消和失败的情况下调用它,只需将其包装在IDisposable中,并在异步工作流中“使用”它。希望我正确理解了您的用例
async {
use _ = { new IDisposable with member __.Dispose() = cancel_callback() }
// Or if only on Cancel case
use! cancelHandler = Async.OnCancel(fun () -> cancel_callback())
// Do rest of your workflow here...
}
要使非托管代码的互操作正常工作是很棘手的,尤其是在有回调的情况下。有很多事情会让你绊倒,比如打电话给会议。因此,我不能保证下面的代码能正常工作,但也许你可以从它开始,调整到适合你的状态 通常我用C语言定义互操作代码,但F语言也支持它
open System
open System.Runtime.InteropServices
// Contains F# PInvkoe for the call_callback, cancel_callback
// assuming they are exported by "my.dll"
// Note this relies on standard calling convention (default in Windows)
module CallbackInterop =
// handle* call_callback(void (*callback)(int));
[<DllImport("my.dll", CallingConvention=CallingConvention.StdCall)>]
extern nativeint call_callback(nativeint callback);
// void cancel_callback(handle* h);
[<DllImport("my.dll", CallingConvention=CallingConvention.StdCall)>]
extern void cancel_callback(nativeint h);
type CallbackDelegate = delegate of int -> unit
// The CallbackInterop is very low-level, ManagedCallback is a bridge between
// low-level unmanaged function pointers and .NET managed delegates
type ManagedCallback (callback : ManagedCallback -> int -> unit) =
let mutable ghnd = Unchecked.defaultof<GCHandle>
let mutable del = Unchecked.defaultof<Delegate>
let mutable cptr = IntPtr.Zero
let mutable hnd = IntPtr.Zero
member x.Callback (i :int) : unit = callback x i
member x.Start () =
// Creates a delegate for x.Callback
del <- CallbackDelegate x.Callback
// Prevents collection of the Delegate while we are waiting for
// a callback and also prevents the GC from moving the Delegate around
// The delegate also references the ManagedCallback so it also prevents the
// the collection of ManagedCallback
ghnd <- GCHandle.Alloc (del, GCHandleType.Pinned)
// Create function pointer from pinned delegate
cptr <- Marshal.GetFunctionPointerForDelegate del
// Register the function pointer and get a handle back
// After this we are ready for callbacks
hnd <- CallbackInterop.call_callback cptr
interface IDisposable with
member x.Dispose () =
// Usually when implementing unmanaged interop one implements a finalizer
// but due to the setup this object can't be collected while the callback is active
// This means no need for finalizer
try
let h = hnd
// Reset all members
hnd <- IntPtr.Zero
cptr <- IntPtr.Zero
del <- Unchecked.defaultof<Delegate>
// Cancel callback if active
if h <> IntPtr.Zero then
CallbackInterop.cancel_callback h
finally
// Free the GCHandle, ensuring the delegate and ManagedCallback can now be collected
if ghnd <> Unchecked.defaultof<GCHandle> then
ghnd.Free ()
ghnd <- Unchecked.defaultof<GCHandle>
// An async workflow that uses the managed callback
let managedCallback : Async<int> =
Async.FromContinuations <| fun (onSuccess, _, _) ->
// onSuccess is called on success, the other callbacks on failure
// and cancellations, call them as needed
// The callback for the ManagedCallback, we dispose the callback when we receive a value
// and then call onSuccess
let cb (mc : ManagedCallback) i =
let d : IDisposable = mc :> IDisposable
d.Dispose ()
onSuccess i
// Setup and start the ManagedCallback
let mc = new ManagedCallback (cb)
mc.Start ()
开放系统
open System.Runtime.InteropServices
//包含调用回调、取消回调的F#PInvkoe
//假设它们是通过“my.dll”导出的
//注意:这依赖于标准调用约定(Windows中的默认值)
模块回调互操作=
//句柄*call_callback(void(*callback)(int));
[]
外部本地调用\u回调(本地回调);
//作废取消回调(句柄*h);
[]
外部无效取消回调(nativeint h);
类型CallbackDelegate=整数->单位的委托
//CallbackInterop是非常低级的,ManagedCallback是
//低级非托管函数指针和.NET托管委托
键入ManagedCallback(回调:ManagedCallback->int->unit)=
设可变ghnd=Unchecked.defaultof
设可变del=Unchecked.defaultof
设可变cptr=IntPtr.Zero
设可变hnd=IntPtr.Zero
成员x.回调(i:int):单位=回调x i
成员x.开始()=
//为x.Callback创建委托
德尔