Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/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
Unix 为函数设置计时器_Unix_Time_Timer_Signals_Ocaml - Fatal编程技术网

Unix 为函数设置计时器

Unix 为函数设置计时器,unix,time,timer,signals,ocaml,Unix,Time,Timer,Signals,Ocaml,我已经定义了一个值列表:data:int list和一个函数f:int->unit,以及一段代码: for i = 0 to (List.length data) - 1 do let d = List.nth data i in f d done 现在,我想为f设置一个最大运行时间。例如,如果fd超过某个时间maximal,fd的执行停止,我们继续执行数据的下一个元素 有人知道怎么做吗 更新1: 在评论之后,我想补充一点,将f应用到数据的大部分元素将引发异常。这是正常的,也是可以接受

我已经定义了一个值列表:
data:int list
和一个函数
f:int->unit
,以及一段代码:

for i = 0 to (List.length data) - 1 do
  let d = List.nth data i in
  f d
done
现在,我想为
f
设置一个最大运行时间。例如,如果
fd
超过某个时间
maximal
fd
的执行停止,我们继续执行
数据的下一个元素

有人知道怎么做吗

更新1:

在评论之后,我想补充一点,将
f
应用到
数据的大部分元素
将引发异常。这是正常的,也是可以接受的。因此,代码如下所示:

List.iter
  (fun d ->
     try
       (f d)
     with
     | e ->
       printf "%s\n" (Printexc.to_string e))
data

这样的东西可能适合你:

exception Timeout

let run_with_timeout t f x =
    try
        Sys.set_signal Sys.sigalrm (Sys.Signal_handle (fun _ -> raise Timeout));
        ignore (Unix.alarm t);
        f x;
        ignore (Unix.alarm 0);
        Sys.set_signal Sys.sigalrm Sys.Signal_default
    with Timeout -> Sys.set_signal Sys.sigalrm Sys.Signal_default
下面是一个演示其工作原理的课程:

$ ocaml
        OCaml version 4.00.1

# #load "unix.cma";;
# #use "rwt.ml";;
exception Timeout
val run_with_timeout : int -> ('a -> 'b) -> 'a -> unit = <fun>
# run_with_timeout 2 Printf.printf "yes\n";;
yes
- : unit = ()
# run_with_timeout 2 (fun () -> while true do () done) ();;
- : unit = ()
#
(这段代码还没有经过彻底的测试,但它展示了一种可行的方法。)

更新


如注释所示,如果
fx
可能引发异常(或者如果您将报警用于其他目的),则此代码不适用。我鼓励gsg发布他/她的改进解决方案。编辑似乎已被拒绝。

这是基于Jeffrey的回答,并进行了一些修改以提高异常安全性:

exception Timeout

let run_with_timeout timeout f x =
  let old_handler = Sys.signal Sys.sigalrm
    (Sys.Signal_handle (fun _ -> raise Timeout)) in
  let finish () =
    ignore (Unix.alarm 0);
    ignore (Sys.signal Sys.sigalrm old_handler) in
  try
    ignore (Unix.alarm timeout);
    ignore (f x);
    finish ()
  with Timeout -> finish ()
   | exn -> finish (); raise exn

您应该按如下方式编写循环:
List.iter f data
。您的方法引入了不必要的二次复杂性。(对不起,这不是对你的计时问题的回答。)虽然我认为这是最正确的方法,但如果
fx
上升,你会遇到麻烦。将有一个挂起的
SIGALRM
,并且仍将安装引发
超时的处理程序。此外,如果存在一个现有的
SIGALRM
处理程序,无论
fx
是否提升,它都将被无声地踩踏。更好的方法是使用
Sys.signal
保存旧的处理程序,并无条件地恢复它:类似于
try。。。;使用exn->finish()完成();exn
,其中
finish
恢复旧处理程序并取消任何挂起的报警。阿门。但是,如果事情处于已知状态(代码不是通用库的一部分,等等),也许一个粗略的解决方案是可以的。@gsg
如果fx引发
==>您的意思是当
fx
引发异常时,您会遇到麻烦吗?我的
fx
的一部分将以异常结束,因此此代码不适用?是的,这就是我的意思。如果
fx
可能引发异常,则需要对代码进行一点修改。@gsg此计时器应该包装整个
fx
,这很复杂(这就是它需要时间的原因),并且可能引发多种类型的异常。我真的很想更正它,但我不熟悉Sys或Unix。我将要更新OP,你能帮我解决吗?谢谢!我还是不确定编辑出了什么事?哦,好吧。
exception Timeout

let run_with_timeout timeout f x =
  let old_handler = Sys.signal Sys.sigalrm
    (Sys.Signal_handle (fun _ -> raise Timeout)) in
  let finish () =
    ignore (Unix.alarm 0);
    ignore (Sys.signal Sys.sigalrm old_handler) in
  try
    ignore (Unix.alarm timeout);
    ignore (f x);
    finish ()
  with Timeout -> finish ()
   | exn -> finish (); raise exn