簡體   English   中英

Python3 用線程詛咒

[英]Python3 curses with threading

我有一個使用curses 和線程的應用程序,它等待輸入,然后將其發布到隊列中。 屏幕很快就會被奇怪的字符損壞。 最初,我嘗試將“with threading.Lock()”添加到與curses 相關的所有內容中,以防止線程相互破壞。 那沒有用。

為了簡單起見,我將應用程序精簡到我能想出的最短代碼量來顯示問題。 在代碼中,我從線程向屏幕添加一個字符串,並刷新。 很快,錯誤就會出現在整個屏幕上。 這可能是由於轉義序列被寫入屏幕並在寫入過程中被另一個線程中斷造成的。

有沒有正確或更聰明的方法,或者一個聰明的技巧來讓詛咒與其他線程很好地發揮作用?

#!/usr/bin/python3
# date: 2020.02.29 
# platform: raspberry pi 3b+
# python version: 3.5.3
#
# intent: figure out how to get threads to pass messages to the main thread
#         without failure. failure: exiting unexpectedly, throwing exceptions, or corrupting the display.
#
# -v0.0: no thread locking; 5 threads; fails almost instantly.
# -v0.1: thread locking every call to curses methods after threads started; still fails.
# -v0.2: reduced # of threads to 1; takes longer to fail.

import sys,os,time,curses,threading

def threadfunc(ch,blocktime,stdscr):
    while True:
        threadname = 'thread {}'.format(ch)
        with threading.Lock():
            stdscr.addstr(int(curses.LINES/3)-2,int((curses.COLS - len(threadname))/2),threadname)
            stdscr.refresh()
        time.sleep(blocktime)

def main(stdscr):
    if curses.has_colors() == True:
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1,curses.COLOR_GREEN,curses.COLOR_BLUE)
        curses.init_pair(2,curses.COLOR_WHITE,curses.COLOR_RED)
        stdscr.bkgd(' ',curses.color_pair(1))

    curses.curs_set(0)      # cursor off.
    curses.noecho()
    curses.cbreak()
    stdscr.keypad(True)     # receive special messages.

    # instantiate a small window to hold responses to keyboard messages.
    xmsg = 32
    ymsg = 1
    msgwin = curses.newwin(ymsg,xmsg,int(curses.LINES/3),int((curses.COLS - xmsg)/2))
    msgwin.bkgd(' ',curses.color_pair(2))
    stdscr.noutrefresh()
    msgwin.noutrefresh()
    curses.doupdate()

    # make threads, each with slightly different sleep time:
    threadcount = 5
    t = []
    for i in range(threadcount):
        t.append(threading.Thread(target=threadfunc,name='t{}'.format(i),args=(chr(ord('0')+i),0.2+0.02*i,stdscr),daemon=True))
        t[i].start()

    while True:
        with threading.Lock():
            key = stdscr.getch()    # wait for a character; returns an int; does not raise an exception.
        if key == 0x1b:             # escape key exits
            exitmsg = 'exiting...'
            with threading.Lock():
                msgwin.erase()
                msgwin.addstr(0,int((xmsg-len(exitmsg))/2),exitmsg)
            break
        else:
            feedback = 'received {}'.format(chr(key))
            with threading.Lock():
                msgwin.erase()
                msgwin.addstr(0,int((xmsg-len(feedback))/2),feedback)

        with threading.Lock():
            msgwin.refresh()

    del t           # is this the proper way to destroy an object?
    exitmsg = 'press any key to exit'
    stdscr.addstr(int(curses.LINES/2),int((curses.COLS-len(exitmsg))/2),exitmsg)
    stdscr.getkey()

    stdscr.keypad(False)
    curses.nocbreak()
    curses.echo()
    curses.endwin()

if __name__ == '__main__':
    # Must happen BEFORE calling the wrapper, else escape key has a 1 second delay after pressing:
    os.environ.setdefault('ESCDELAY','100') # in mS; default: 1000
    curses.wrapper(main)

訣竅是使用noutrefresh() / doupdate()而不是refresh()調用。 doupdate()更改,然后在一個線程中處理doupdate()

#!/usr/bin/python3
# date: 2020.02.29 
# platform: raspberry pi 3b+
# python version: 3.5.3
#
# intent: figure out how to get threads to pass messages to the main thread
#         without failure. failure: exiting unexpectedly, throwing exceptions, or corrupting the display.
#
# -v0.0: no thread locking; 5 threads; fails almost instantly.
# -v0.1: thread locking every call to curses methods after threads started; still fails.
# -v0.2: reduced # of threads to 1; takes longer to fail.
# -v0.3: no thread locking; using redrawln, redrawwin to fix corruption
# -v0.4: no redrawln; use noutrefresh/doupdate instead of refresh

import sys,os,time,curses,threading

import locale

locale.setlocale(locale.LC_ALL, '')
code = locale.getpreferredencoding()

def threadfunc(ch,blocktime,stdscr):
    while True:
        threadname = 'thread {}'.format(ch)
        stdscr.addstr(int(curses.LINES/3)-2,int((curses.COLS - len(threadname))/2),threadname)
        # stdscr.redrawln(int(curses.LINES/3)-2, 1)
        stdscr.noutrefresh()
        curses.doupdate()
        time.sleep(blocktime)

def main(stdscr):
    if curses.has_colors() == True:
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1,curses.COLOR_GREEN,curses.COLOR_BLUE)
        curses.init_pair(2,curses.COLOR_WHITE,curses.COLOR_RED)
        stdscr.bkgd(' ',curses.color_pair(1))

    curses.curs_set(0)      # cursor off.
    curses.noecho()
    curses.cbreak()
    stdscr.keypad(True)     # receive special messages.

    # instantiate a small window to hold responses to keyboard messages.
    xmsg = 32
    ymsg = 1
    msgwin = curses.newwin(ymsg,xmsg,int(curses.LINES/3),int((curses.COLS - xmsg)/2))
    msgwin.bkgd(' ',curses.color_pair(2))

    stdscr.noutrefresh()
    msgwin.noutrefresh()
    curses.doupdate()

    # make threads, each with slightly different sleep time:
    threadcount = 5
    t = []
    for i in range(threadcount):
        t.append(threading.Thread(target=threadfunc,name='t{}'.format(i),args=(chr(ord('0')+i),0.2+0.02*i,stdscr),daemon=True))
        t[i].start()

    while True:
        key = stdscr.getch()    # wait for a character; returns an int; does not raise an exception.
        if key == 0x1b:             # escape key exits
            exitmsg = 'exiting...'
            msgwin.erase()
            msgwin.addstr(0,int((xmsg-len(exitmsg))/2),exitmsg)
            break
        else:
            feedback = 'received {}'.format(chr(key))
            msgwin.erase()
            msgwin.addstr(0,int((xmsg-len(feedback))/2),feedback)
        msgwin.noutrefresh()

    del t           # is this the proper way to destroy an object?
    exitmsg = 'press any key to exit'
    stdscr.addstr(int(curses.LINES/2),int((curses.COLS-len(exitmsg))/2),exitmsg)
    stdscr.getkey()

    stdscr.keypad(False)
    curses.nocbreak()
    curses.echo()
    curses.endwin()

if __name__ == '__main__':
    # Must happen BEFORE calling the wrapper, else escape key has a 1 second delay after pressing:
    os.environ.setdefault('ESCDELAY','100') # in mS; default: 1000
    curses.wrapper(main)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM