如果它位于不同的线程上,则在Python Curses窗口上的getch不会返回KEY_RESIZE

时间:2015-11-24 23:58:49

标签: python multithreading ncurses python-multithreading python-curses

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会破坏屏幕输出。我也没有处理在此代码中修复终端,因此您需要重置它以使其恢复正常。

1 个答案:

答案 0 :(得分:0)

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

ncurses有一个编译时配置,它提供了基本的支持(即一个更好的起点),但是你不太可能在预先打包的形式中遇到这种情况,尽管它是在几年前推出的(参见FAQ {{3 }})。

进一步阅读:

在初始化期间,ncurses为using UnityEngine; using System.Collections; using System.Collections.Generic; using PlayFab; using PlayFab.ClientModels; public class PlayFabManager : MonoBehaviour { public string PlayFabId; void Login(string titleId) { LoginWithCustomIDRequest request = new LoginWithCustomIDRequest() { TitleId = titleId, CreateAccount = true, CustomId = SystemInfo.deviceUniqueIdentifier }; PlayFabClientAPI.LoginWithCustomID(request, (result) => { PlayFabId = result.PlayFabId; Debug.Log("Got PlayFabID: " + PlayFabId); if(result.NewlyCreated) { Debug.Log("(new account)"); } else { Debug.Log("(existing account)"); SetUserData(); GetUserData(); } }, (error) => { Debug.Log("Error logging in player with custom ID:"); Debug.Log(error.ErrorMessage); }); } void GetUserData() { GetUserDataRequest request = new GetUserDataRequest() { PlayFabId = PlayFabId, Keys = null }; PlayFabClientAPI.GetUserData(request,(result) => { Debug.Log("Got user data:"); if ((result.Data == null) || (result.Data.Count == 0)) { Debug.Log("No user data available"); } else { Debug.Log (result.Data["age"].Value); foreach (var item in result.Data) { Debug.Log(" " + item.Key + " == " + item.Value.Value); } } }, (error) => { Debug.Log("Got error retrieving user data:"); Debug.Log(error.ErrorMessage); }); } void SetUserData() { UpdateUserDataRequest request = new UpdateUserDataRequest() { Data = new Dictionary(){ {"Ancestor", "Arthur"}, {"Successor", "Fred"} } }; PlayFabClientAPI.UpdateUserData(request, (result) => { Debug.Log("Successfully updated user data"); }, (error) => { Debug.Log("Got error setting user data Ancestor to Arthur"); Debug.Log(error.ErrorDetails); }); } void Awake(){ PlayFabSettings.TitleId = "HIDDEN"; //your title id goes here. } // Use this for initialization void Start () { Login ("HIDDEN"); } // Update is called once per frame void Update () { } } 和其他一些人添加了信号处理程序。使用SIGWINCH,我可以看到python正在捕获strace并忽略它:

SIGWINCH

由于 python 已经建立了信号处理程序, ncurses 不再能够看到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 ,并且不会传递SIGWINCH。据推测,这是在python中完成的,以减轻线程配置中信号的问题。

也许是相关信息:

相关问题