Sof*_*mur 5 unix time ocaml signals timer
我已经定义了一个值列表: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
Run Code Online (Sandbox Code Playgroud)
现在,我想设置一个最大运行时间f.例如,如果f d超过一定时间maximal,执行f d停止,我们继续执行下一个元素data.
有谁知道怎么做?
UPDATE1:
在评论之后,我想补充一点,对f大部分元素的应用data最终会引发异常.这是正常的并被接受.所以代码看起来像:
List.iter
(fun d ->
try
(f d)
with
| e ->
printf "%s\n" (Printexc.to_string e))
data
Run Code Online (Sandbox Code Playgroud)
这样的事可能适合你:
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
Run Code Online (Sandbox Code Playgroud)
这是一个展示其工作原理的会话:
$ 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 = ()
#
Run Code Online (Sandbox Code Playgroud)
你的代码是这样的:
List.iter (run_with_timeout 10 f) data
Run Code Online (Sandbox Code Playgroud)
(此代码未经过彻底的测试,但它显示了可行的方法.)
更新
正如评论所示,如果f x可能抛出异常(或者如果您将警报用于其他目的),则此代码不适用.我鼓励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
Run Code Online (Sandbox Code Playgroud)