中断 OCaml 中的调用
Interrupt a call in OCaml
如果计算时间太长,我想中断通话,就像这样
try
do_something ()
with Too_long -> something_else ()
在 OCaml 中可以做类似的事情吗?函数do_something
不能修改。
(我猜你在Linux)
详细了解 signal(7)-s. You could use Ocaml's Sys.signal
for Sys.sigalarm
and Unix 模块(特别是 Unix.setitimer
)
标准库中没有 built-in 工具来执行此精确操作,但实现起来相当简单。使用 Thread
模块,运行 一个线程来执行您的主程序和一个监控线程,如果它持续时间太长将终止该程序。这是一个开始的实现:
type 'a state =
| Running
| Finished of 'a
| Failed of exn
| Cancelled of 'a
let bounded_run d f g x =
let state = ref Running in
let p = ref None in
let m = ref None in
let cancel t' = match !t' with
| Some(t) -> Thread.kill t
| None -> ()
in
let program () =
(try state := Finished(f x)
with exn -> state := Failed (exn));
cancel m;
in
let monitor () =
Thread.delay d;
match !state with
| Running -> cancel p; state := Cancelled(g x)
| _ -> ()
in
p := Some(Thread.create program ());
m := Some(Thread.create monitor p);
(match !m with
| None -> ()
| Some(t) -> Thread.join t);
!state
调用 bounded_run d f g x
运行s f x
最多 d
秒和 returns Finished(f x)
如果计算 运行s 在给定的时间内。如果计算抛出异常,它可能 return Failed(exn)
。当计算时间过长时,returned 值为 Cancelled(g x)
.
这个实现有很多默认值,例如,状态和 returned 值应该有不同的类型(值 Running
不应该在 returned 类型中),它不使用互斥锁来阻止对 p
和 m
变量的并发访问,这些变量持有对我们使用的线程的引用。虽然它的边缘很粗糙,但这应该可以帮助您入门,但要获得更高级的用法,您还应该学习 Event 或第三方库,例如 Lwt 或 Async – 前者需要您更改函数。
一般来说,中断函数的唯一方法是使用信号,正如 Basile 所建议的那样。不幸的是,控制流将转移到信号处理程序,因此您将无法 return 一个您喜欢的值。要获得更多 fine-grained 控制,您可以 运行 您 do_something
在单独的线程中。第一近似值是以下函数:
exception Timeout
let with_timeout timeout f =
let result = ref None in
let finished = Condition.create () in
let guard = Mutex.create () in
let set x =
Mutex.lock guard;
result := Some x;
Mutex.unlock guard in
Mutex.lock guard;
let work () =
let x = f () in
set x;
Condition.signal finished in
let delay () =
Thread.delay timeout;
Condition.signal finished in
let task = Thread.create work () in
let wait = Thread.create delay () in
Condition.wait finished guard;
match !result with
| None ->
Thread.kill task;
raise Timeout
| Some x ->
Thread.kill wait;
x
线程和信号函数的解决方案都有一些缺点。例如,线程在 OCaml 中在特定的中断点切换,通常这是任何分配。因此,如果您的代码不执行任何分配或外部调用,那么它可能永远不会屈服于其他线程,并且将永远 运行 。这种函数的一个很好的例子是 let rec f () = f ()
。在这种情况下,您应该 运行 在另一个进程而不是线程中使用您的函数。 OCaml 中有许多用于多处理的库,仅举几例:
如果计算时间太长,我想中断通话,就像这样
try
do_something ()
with Too_long -> something_else ()
在 OCaml 中可以做类似的事情吗?函数do_something
不能修改。
(我猜你在Linux)
详细了解 signal(7)-s. You could use Ocaml's Sys.signal
for Sys.sigalarm
and Unix 模块(特别是 Unix.setitimer
)
标准库中没有 built-in 工具来执行此精确操作,但实现起来相当简单。使用 Thread
模块,运行 一个线程来执行您的主程序和一个监控线程,如果它持续时间太长将终止该程序。这是一个开始的实现:
type 'a state =
| Running
| Finished of 'a
| Failed of exn
| Cancelled of 'a
let bounded_run d f g x =
let state = ref Running in
let p = ref None in
let m = ref None in
let cancel t' = match !t' with
| Some(t) -> Thread.kill t
| None -> ()
in
let program () =
(try state := Finished(f x)
with exn -> state := Failed (exn));
cancel m;
in
let monitor () =
Thread.delay d;
match !state with
| Running -> cancel p; state := Cancelled(g x)
| _ -> ()
in
p := Some(Thread.create program ());
m := Some(Thread.create monitor p);
(match !m with
| None -> ()
| Some(t) -> Thread.join t);
!state
调用 bounded_run d f g x
运行s f x
最多 d
秒和 returns Finished(f x)
如果计算 运行s 在给定的时间内。如果计算抛出异常,它可能 return Failed(exn)
。当计算时间过长时,returned 值为 Cancelled(g x)
.
这个实现有很多默认值,例如,状态和 returned 值应该有不同的类型(值 Running
不应该在 returned 类型中),它不使用互斥锁来阻止对 p
和 m
变量的并发访问,这些变量持有对我们使用的线程的引用。虽然它的边缘很粗糙,但这应该可以帮助您入门,但要获得更高级的用法,您还应该学习 Event 或第三方库,例如 Lwt 或 Async – 前者需要您更改函数。
一般来说,中断函数的唯一方法是使用信号,正如 Basile 所建议的那样。不幸的是,控制流将转移到信号处理程序,因此您将无法 return 一个您喜欢的值。要获得更多 fine-grained 控制,您可以 运行 您 do_something
在单独的线程中。第一近似值是以下函数:
exception Timeout
let with_timeout timeout f =
let result = ref None in
let finished = Condition.create () in
let guard = Mutex.create () in
let set x =
Mutex.lock guard;
result := Some x;
Mutex.unlock guard in
Mutex.lock guard;
let work () =
let x = f () in
set x;
Condition.signal finished in
let delay () =
Thread.delay timeout;
Condition.signal finished in
let task = Thread.create work () in
let wait = Thread.create delay () in
Condition.wait finished guard;
match !result with
| None ->
Thread.kill task;
raise Timeout
| Some x ->
Thread.kill wait;
x
线程和信号函数的解决方案都有一些缺点。例如,线程在 OCaml 中在特定的中断点切换,通常这是任何分配。因此,如果您的代码不执行任何分配或外部调用,那么它可能永远不会屈服于其他线程,并且将永远 运行 。这种函数的一个很好的例子是 let rec f () = f ()
。在这种情况下,您应该 运行 在另一个进程而不是线程中使用您的函数。 OCaml 中有许多用于多处理的库,仅举几例: