为功能设置计时器

时间:2013-11-10 00:38:59

标签: 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设置最长运行时间。例如,如果f d超过特定时间maximalf d的执行就会停止,我们继续使用data的下一个元素。

有谁知道怎么做?

UPDATE1:

在评论之后,我想补充一点,fdata的大部分元素的应用最终会引发异常。这是正常的并被接受。所以代码看起来像:

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

2 个答案:

答案 0 :(得分:5)

这样的事可能适合你:

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 = ()
#

您的代码将是这样的:

List.iter (run_with_timeout 10 f) data

(此代码未经过彻底的测试,但它显示了可行的方法。)

<强>更新

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

答案 1 :(得分:1)

这是基于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