2017-08-12 80 views
2

我有一个线程类,我想在我的主函数中多次启动/停止我的线程。我用this linkthis method来解决我的问题。下面是一个简单的线程,其打印按键控制台:使用Python控制线程循环

global isWindows 

isWindows = False 


try: 
    from win32api import STD_INPUT_HANDLE 
    from win32console import GetStdHandle, KEY_EVENT, ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT 
    import win32gui 
    import threading 
    from time import sleep 
    import sys 
    isWindows = True 
except ImportError as e: 
    import sys 
    import select 
    import termios 


class KeyPoller(threading.Thread): 

    def __init__(self): 
     super(KeyPoller, self).__init__() 
     #threading.Thread.__init__(self) 
     self.stop_event = threading.Event() 
     global isWindows 
     if isWindows: 
      self.readHandle = GetStdHandle(STD_INPUT_HANDLE) 
      self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT) 

      self.curEventLength = 0 
      self.curKeysLength = 0 

      self.capturedChars = [] 
     else: 
      # Save the terminal settings 
      self.fd = sys.stdin.fileno() 
      self.new_term = termios.tcgetattr(self.fd) 
      self.old_term = termios.tcgetattr(self.fd) 

      # New terminal setting unbuffered 
      self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) 
      termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) 

    def poll(self): 
     if isWindows: 
      if not len(self.capturedChars) == 0: 
       return self.capturedChars.pop(0) 

      eventsPeek = self.readHandle.PeekConsoleInput(10000) 

      if len(eventsPeek) == 0: 
       return None 

      if not len(eventsPeek) == self.curEventLength: 
       for curEvent in eventsPeek[self.curEventLength:]: 
        if curEvent.EventType == KEY_EVENT: 
         if ord(curEvent.Char) == 0 or not curEvent.KeyDown: 
          pass 
         else: 
          curChar = str(curEvent.Char) 
          self.capturedChars.append(curChar) 
       self.curEventLength = len(eventsPeek) 

      if not len(self.capturedChars) == 0: 
       return self.capturedChars.pop(0) 
      else: 
       return None 
     else: 
      dr,dw,de = select.select([sys.stdin], [], [], 0) 
      if not dr == []: 
       return sys.stdin.read(1) 
      return None 

    def stop(self): 
     print("stopping the thread") 
     self.stop_event.set() 

    def stopped(self): 
     return self.stop_event.is_set() 

    def run(self): 
     while not self.stopped(): 
      c=self.poll() 
      if not c is None: 
       print(c) 

if __name__=='__main__': 

    thr=KeyPoller() 
    print("starting the thread #1") 
    thr.start() 
    sleep(5) 
    print("stopping the thread #1") 
    # sadly if you press any key in this time it would be saved and printed after thr2.start 
    thr.stop() 
    thr.join() 
    sleep(5) 
    thr2=KeyPoller() 
    print("starting the thread #2") 
    thr2.start() 
    sleep(5) 
    print("stopping the thread #2") 
    thr2.stop() 
    print("Exiting the whole program") 

我的问题是,当我打电话thr.stop()并尝试按某些按键退出while循环,似乎该线程已经停止,但是当我调用thr2.start()它打印从我的线程的第一个实例的旧键击,似乎所有击键仍然存在,无论我是否调用停止函数。

回答

1

从我的角度来看,我没有看到初始化treading.event()作为实例变量的意义。事件是针对线程/进程同步的,如果你在一个实例中声明了它,那么其他实例就不能被看到。

话虽如此,给定你的代码,我会使用一个布尔变量为stop_event。这在Linux环境中适用于我。

class KeyPoller(threading.Thread): 

    def __init__(self): 
     super(KeyPoller, self).__init__() 
     #threading.Thread.__init__(self) 
     self.stop_event = False 
     global isWindows 
     if isWindows: 
      self.readHandle = GetStdHandle(STD_INPUT_HANDLE) 
      self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT) 

      self.curEventLength = 0 
      self.curKeysLength = 0 

      self.capturedChars = [] 
     else: 
      # Save the terminal settings 
      self.fd = sys.stdin.fileno() 
      self.new_term = termios.tcgetattr(self.fd) 
      self.old_term = termios.tcgetattr(self.fd) 

      # New terminal setting unbuffered 
      self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) 
      termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) 

    def poll(self): 
     if isWindows: 
      if not len(self.capturedChars) == 0: 
       return self.capturedChars.pop(0) 

      eventsPeek = self.readHandle.PeekConsoleInput(10000) 

      if len(eventsPeek) == 0: 
       return None 

      if not len(eventsPeek) == self.curEventLength: 
       for curEvent in eventsPeek[self.curEventLength:]: 
        if curEvent.EventType == KEY_EVENT: 
         if ord(curEvent.Char) == 0 or not curEvent.KeyDown: 
          pass 
         else: 
          curChar = str(curEvent.Char) 
          self.capturedChars.append(curChar) 
       self.curEventLength = len(eventsPeek) 

      if not len(self.capturedChars) == 0: 
       return self.capturedChars.pop(0) 
      else: 
       return None 
     else: 
      dr,dw,de = select.select([sys.stdin], [], [], 0) 
      if not dr == []: 
       return sys.stdin.read(1) 
      return None 

    def stop(self): 
     print("stopping the thread") 
     self.stop_event = True 

    def stopped(self): 
     return self.stop_event 

    def run(self): 
     while not self.stopped(): 
      c=self.poll() 
      if not c is None: 
       print(c) 
+0

感谢您的提示,我使用Windows,但仍然是,我面临同样的问题。 –

+0

与此功能你的答案没有工作,但我试图用一个简单的功能取代它的工作。谢谢。 –