gpt4 book ai didi

multithreading - OCaml 中的线程延迟和键盘事件

转载 作者:行者123 更新时间:2023-12-04 07:26:08 26 4
gpt4 key购买 nike

这是 OCaml 中的一个简单游戏循环。显示状态,接收输入,进入状态。通过在每个循环中延迟线程 0.025 秒,每秒帧数被限制为 40。

主文件:

let rec main (* state *) frame_time =
(* Display state here. *)
Input.get_input ();
(* Advance state by one frame here. *)
(* If less than 25ms have passed, delay until they have. *)
if((Sys.time ()) < (frame_time +. 0.025)) then
Thread.delay ((frame_time +. 0.025) -. (Sys.time ()));
main (* next_state *) (Sys.time ())
;;

let init =
Graphics.open_graph " 800x500";
let start_time = (Sys.time ()) in
main (* start_state *) start_time
;;

对于此示例, get_input函数只是将击键打印到窗口。

输入.ml:

let get_input () =
let s = Graphics.wait_next_event
[Graphics.Key_pressed] in
if s.Graphics.keypressed then
Graphics.draw_char s.Graphics.key
;;

Makefile 便于测试:
main: input.cmo main.cmo
ocamlfind ocamlc -o $@ unix.cma -thread threads.cma graphics.cma $^
main.cmo: main.ml
ocamlfind ocamlc -c $< -thread
input.cmo: input.ml
ocamlfind ocamlc -c $<

这在大多数情况下有效,但是当按键被非常快地按下时,程序会因以下错误而崩溃:
Fatal error: exception Unix.Unix_error(2, "select", "")
我相信它与 Thread.delay有关.导致此问题的原因是什么,实现恒定 FPS 的最佳方法是什么?

最佳答案

我不确定发生了什么(这取决于 Thread.delay 的实现,我不知道)。但是,错误 2 是 Unix.EAGAIN ,这表示内核资源暂时短缺。顾名思义,您可能应该再次尝试执行 Thread.delay 。如果我使用 try ... with要捕获 Unix.Unix_error 异常,除了 EAGAIN 正在交付之外,我没有看到其他错误。如果我只是打印一条消息并继续,该程序似乎可以工作。至少,它会继续向窗口回显字符并且不会崩溃。我在 OS X 10.7 (Lion) 中工作。它可能对你有不同的作用。

编辑

此代码的另一个可能问题是 Sys.time()返回处理器时间,它只会在进程进行实际计算时增加。在进程等待输入时它不会增加。这意味着延迟总是会被调用,即使你在两次按键之间等待了很长时间(这让我困惑了一段时间)。使用 Unix.gettimeofday () 可能更好,返回挂钟时间。

编辑 2

经过更多的研究和测试,我相信Unix.EAGAIN错误告诉您完全延迟被某个事件中断。在您的情况下,中断事件是角色的到来(我相信)。因此,如果您想等待全部时间,则应将单个调用替换为 Thread.delay()。带一个循环。

这为您的主代码提供了如下内容:

let rec main (* state *) frame_time =
(* Display state here. *)
Input.get_input ();
(* Advance state by one frame here. *)
(* If less than 25ms have passed, delay until they have. *)
let rec delay () =
let duration = frame_time +. 0.025 -. Unix.gettimeofday () in
if duration > 0.0 then
try
Thread.delay duration
with Unix.Unix_error (Unix.EAGAIN, _, _) -> delay ()
in
delay ();
main (* next_state *) (Unix.gettimeofday ())
;;

let init =
Graphics.open_graph " 800x500";
let start_time = (Unix.gettimeofday ()) in
main (* start_state *) start_time
;;

(如果您使用 Unix.select 进行延迟,则可以消除对线程的依赖。但由于其他原因,您可能仍然需要它们。代码看起来相同,只是错误是 EINTR 而不是 EAGAIN。)

关于multithreading - OCaml 中的线程延迟和键盘事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10807428/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com