使用ncurses + python防止竞争条件

时间:2014-04-13 18:28:01

标签: python multithreading ncurses curses

我遇到的问题类似于这篇文章中的问题

C, junk appearing on screen using curses

但是,我正在使用python。我写了一个包装器Screen类,它以更方便的方式包装了curses模块。我喜欢这样的

def getKeyCode(self):                                                                                                                         
    with self._curses_lock:                                                                                                                   
        self._curses_screen.nodelay(False)                                                                                                    

    c = self._curses_screen.getch()                                                                                                           
    if c == 27:                                                                                                                               
        with self._curses_lock:                                                                                                               
            self._curses_screen.nodelay(True)                                                                                                 
        next_c = self._curses_screen.getch()                                                                                                  

        with self._curses_lock:                                                                                                               
            self._curses_screen.nodelay(False)                                                                                                

    return c          

以及归结为此

的写作
        with self._curses_lock:                                                                                                               
            self._curses_screen.addstr(y, x, out_string, attr)

getKeyCode由一个单独的python线程调用,该线程在getch中大部分时间都在等待,当按下一个键时,它会被添加到一个Queue中。在另一个(主)线程上,我有一个事件循环,它从队列中获取事件,执行重新绘制并刷新屏幕。

我知道ncurses持有共享状态,我添加了一堆threading.Locks以防止竞争条件,但如果我按住箭头键,偶尔我会得到垃圾。 我猜这是因为getch在ncurses中被释放,而另一个线程正在进行重新绘制。这弄乱了重画的状态,给出了奇怪的结果。我显然不能让我的getKeyCode线程持有锁,因为这意味着在getch返回之前根本不会重新绘制,也不想让getch非阻塞,因为我会1)没有真正解决问题, 2)有一个不断运行的线程,可以将CPU使用率提高到100%。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

我解决了这个问题。我用

设置getch非阻塞
self._curses_screen.nodelay(True) 

然后我不是在curses中等待,而是在stdin上选择。当select返回时,一些东西可用,我可以锁定并获得对ncurses后端的独占访问,保证我将立即返回可用的内容并释放锁。

def getKeyCode(self):                                                                                                                         
    select.select([sys.stdin], [], [])                                                                                                        

    with self._curses_lock:                                                                                                                   

        c = self._curses_screen.getch()                                                                                                       
        if c == 27:                                                                                                                           
            next_c = self._curses_screen.getch()                                                                                              

    return c