Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asynchronous F#:从接受回调并返回取消句柄的函数创建异步_Asynchronous_F#_Ffi - Fatal编程技术网

Asynchronous F#:从接受回调并返回取消句柄的函数创建异步

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

我对F#还不熟悉,并试图围绕C库编写包装器模块。C库有一个具有此签名的函数:

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创建委托
德尔