2

我正在将 OCaml格式模块转换为 F#,并将问题追溯到使用 OCaml Pervasives at_exit。

val at_exit : (unit -> unit) -> unit

注册要在程序终止时调用的给定函数。at_exit当程序正常或由于未捕获的异常执行退出或终止时,将调用注册的函数。这些函数以“后进先出”的顺序调用:最近添加的函数at_exit首先被调用。

在转换过程中,我注释掉了该行,因为编译器没有将其标记为需要,并且我不希望代码中出现事件。

我检查了FSharp.PowerPack.Compatibility.PervasivesModule使用at_exitVS 对象浏览器,但没有找到。

我确实找到了如何运行代码“at_exit”?以及如何为 F# 应用程序编写退出处理程序?

OCaml 线是

at_exit print_flush 

带有 print_flush 签名: val print_flush : (unit -> unit)

同样在 OCaml 代码的调试会话期间查看它的使用情况时,它看起来像是at_exit在初始化结束时和每次使用对模块的调用结束时都被调用。

任何建议,有关如何执行此操作的提示。这将是我在 F# 中的第一个活动。

编辑

以下是我从 Format 模块中学到的一些内容,应该可以对这个问题有所了解。

Format 模块是一个函数库,用于简单 OCaml 值(例如 int、bool、string)的基本漂亮打印机命令。格式模块有类似的命令print_string,但也有一些命令说把下一行放在有界框中,想想新的左右边距集。所以可以写:

print_string "Hello"

或者

open_box 0; print_string "<<";
open_box 0; print_string "p \/ q ==> r"; close_box();
print_string ">>"; close_box()

诸如open_box和之print_string类的命令由一个循环处理,该循环解释这些命令,然后决定在当前行上打印还是前进到下一行。命令保存在一个队列中,并且有一个状态记录来保存可变值,例如左右边距。

队列和状态需要准备好,从针对工作 OCaml 代码的测试用例调试来看,这似乎是在模块初始化结束时但在第一次调用 Format 模块中的任何函数之前完成的。队列和状态被清理并通过使用机制为下一组命令再次准备好,该机制at_exit识别出对格式模块的初始调用的最后一个匹配帧已被删除,从而触发调用,该调用at_exit推出任何剩余的队列中的命令并重新初始化队列和状态。

因此,调用的顺序print_flush至关重要,而且似乎超出了 OCaml 文档所述的顺序。

4

1 回答 1

2

这应该这样做:

module Pervasives =
    open System
    open System.Threading

    //
    let mutable private exitFunctions : (unit -> unit) list = List.empty

    //
    let mutable private exitFunctionsExecutedFlag = 0

    //
    let private tryExecuteExitFunctions _ =
        if Interlocked.CompareExchange (&exitFunctionsExecutedFlag, 1, 0) = 0 then
            // Run the exit functions in last-in-first-out order.
            exitFunctions
            |> List.iter (fun f -> f ())

    // Register handlers for events which fire when the process exits cleanly
    // or due to an exception being thrown.
    do
        AppDomain.CurrentDomain.ProcessExit.Add tryExecuteExitFunctions
        AppDomain.CurrentDomain.UnhandledException.Add tryExecuteExitFunctions

    //
    let at_exit f =
        // TODO : This function should be re-written using atomic operations
        // for thread-safety!
        exitFunctions <- f :: exitFunctions

和一些代码来测试它:

open System

// Register a couple of handlers to test our code.
Pervasives.at_exit <| fun () ->
    Console.WriteLine "The first registered function has fired!"

Pervasives.at_exit <| fun () ->
    Console.WriteLine "The second registered function has fired!"
    TimeSpan.FromSeconds 1.0
    |> System.Threading.Thread.Sleep
    Console.WriteLine "Exiting the second registered function!"

Pervasives.at_exit <| fun () ->
    Console.WriteLine "The third registered function has fired!"

// Do some stuff in our program
printfn "blah"
printfn "foo"
printfn "bar"

(* The functions we registered with at_exit should be fired here. *)

// Uncomment this to see that our handlers work even when the
// program crashes due to an unhandled exception.
//failwith "Uh oh!"
于 2012-09-28T16:32:14.453 回答