Haskell跨平台NoBuffering getChar

3
Haskell存在Windows中的一个bug,似乎在GHC9中通过WinIO已经修复:getChar忽略了NoBuffering模式 - 直到按下Enter才会执行。

有人建议通过外部调用来解决这个问题:

{-# LANGUAGE ForeignFunctionInterface #-}
import Data.Char
import Foreign.C.Types
getHiddenChar = fmap (chr.fromEnum) c_getch
foreign import ccall unsafe "conio.h getch"
  c_getch :: IO CInt

它有点起作用,但问题是似乎会阻塞控制台输出直到按下某个键,而我正在从不同的线程并发读取按键和写入控制台。请帮忙找到一种在 Windows 上使用 GHC 8.8.x(或至少是 8.10.x)无需缓冲和回显且不会阻止控制台输出读取字符/按键的方法(例如编写外部函数调用-很遗憾,我对此不太了解)。谢谢!(理想情况下,我需要跨平台的方法,但我可以通过条件编译来实现,因此如果仅在 Windows 上可行也可以。上述外部调用已经不跨平台)。
2个回答

1

1
那个特定的 FFI 调用的关键问题在于 unsafe。这使得 getch 在调用(系统)线程中发生。通常,可能需要一些时间的外部调用应该标记为 safe。即使如此,这也有点棘手,因为异常(例如用户按下 Ctrl-C)会被屏蔽。
针对这样的 FFI 调用的真正解决方案是将它们标记为 interruptible,然后正确处理中断。你可以通过检查调用是否成功(基于其返回值)来实现这一点。如果没有成功,则应该检查 errno 是否为 EINTR,并在这种情况下重试,就像任何类似的外部调用一样。但对于一个 interruptible 的调用,如果你得到了 EINTR,则应该在重试之前使用 allowInterrupt 发送异步异常。
注意:上述方法仅适用于大多数进行可中断系统调用并在中断时以失败状态并设置 EINTR 的外部调用。例如执行昂贵的数学计算的外部函数通常根本不可中断。

注意:在同一文件描述符上混合使用基于Handle的I/O和原始FFI I/O似乎是麻烦的源头。


在同一文件描述符上混合使用基于句柄的I/O和原始FFI I/O听起来像是麻烦的配方。即使只有一个线程通过句柄进行写入,而另一个线程通过FFI进行读取,也是如此吗? - esp
1
@esp,我不能确定。可能没问题,但我在那方面不是专家。 - dfeuer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接