0
import curses, threading, sys

def thread():
    a = curses.initscr()
    curses.noecho()
    curses.cbreak()
    a.keypad(True)
    while True:
        char = a.getch()
        if char == curses.KEY_RESIZE: 
            print("key_resize", file=sys.stderr)
        else:
            print("other", file=sys.stderr)

threading.Thread(target=thread).start()

当我自己运行此功能时,一切正常 - KEY_RESIZE 已发送,一切都很好。当我从线程内部调用 getch() 时出现问题 - 关键事件似乎工作正常(我没有彻底或广泛地测试过)但 KEY_RESIZE 从未发送过。

我做错了什么,或者有什么办法可以解决这个问题,以便无论线程如何都可以发送 KEY_RESIZE?

我已经尝试过在线程内外以及 Python 3.4.3 上的两个不同终端仿真器(gnome-terminal 和 konsole)上初始化屏幕。

打印发送到 stderr(重定向到另一个终端),因为 curses 倾向于破坏屏幕输出。我也没有在此代码中修复终端,因此您需要重置它以使其恢复正常。

4

1 回答 1

0

作为一项规则,curses 不是线程安全的。如果您在一个线程中完成所有工作,您可以使 curses 应用程序工作。否则,你会得到意想不到的行为......

ncurses 有一个编译时配置,它提供基本支持(即,更好的起点),但您不太可能以预打包的形式遇到它,尽管它是几年前引入的(参见常见问题解答官方版本)。

进一步阅读:

在初始化期间,ncurses 为SIGWINCH其他一些添加信号处理程序。使用strace,我可以看到 python 正在捕获SIGWINCH并忽略它:

2722  <... futex resumed> )             = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
2722  --- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
2722  rt_sigreturn({mask=[]})           = -1 EINTR (Interrupted system call)
2722  futex(0x7f94d4000c10, FUTEX_WAIT_PRIVATE, 0, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
2722  --- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
2722  rt_sigreturn({mask=[]})           = -1 EINTR (Interrupted system call)
2722  futex(0x7f94d4000c10, FUTEX_WAIT_PRIVATE, 0, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
2722  --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
2722  rt_sigreturn({mask=[]})           = -1 EINTR (Interrupted system call)
2722  write(2, "Exception ignored in: <module 'threading' from '/usr/lib/python3.4/threading.py'>\n", 82) = 82
2722  write(2, "Traceback (most recent call last):\n", 35) = 35
2722  write(2, "  File \"/usr/lib/python3.4/threading.py\", line 1285, in _shutdown\n", 66) = 66
2722  open("/usr/lib/python3.4/threading.py", O_RDONLY|O_CLOEXEC) = 4 

因为python已经建立了一个信号处理程序,ncurses不能再看到SIGWINCH,并且不会传递KEY_RESIZE. 大概这是在 python 中完成的,以减轻线程配置中的信号问题。

也许相关信息:

于 2015-11-25T00:08:14.970 回答