2017-08-12 64 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

與此功能你的答案沒有工作,但我試圖用一個簡單的功能取代它的工作。謝謝。 –