PyQt5中QThread重复启动后信号多次触发问题排查
QThread重启后信号触发次数翻倍问题分析与解决
原代码
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() loadUi('wind.ui', self) self.startButton.clicked.connect(self.start_screen) self.stopButton.clicked.connect(self.stop_screen) self.screen_thread = Screenshot() def start_screen(self): self.screen_thread.start() self.screen_thread.any_signal.connect(self.myfunction) def stop_screen(self): self.screen_thread.stop() def myfunction(self,value): vl = value print(vl, threading.active_count()) class Screenshot(QThread): any_signal = pyqtSignal(int) def __init__(self, parent = None): super(Screenshot, self).__init__(parent) def run(self): value = 1 print('process start') print(threading.active_count()) print(threading.enumerate()) while(True): value += 1 time.sleep(1) self.any_signal.emit(value) def stop(self): print('process stop') self.terminate() print(self.isRunning()) def application(): app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) if __name__ == "__main__": application()
问题描述
编写了上述带有QThread的PyQt5程序,程序包含启动和停止按钮。首次启动时,值正常单次递增输出;点击停止后程序停止,但再次点击启动,输出变为两次,第三次启动输出三次,以此类推。监测线程发现每次仅存在一个线程,请问问题出在哪里?
问题根源
- 信号重复绑定:每次点击启动按钮,都会执行
self.screen_thread.any_signal.connect(self.myfunction),这会给同一个信号重复绑定同一个槽函数。第一次绑定后槽函数触发1次,第二次绑定后触发2次,以此类推,导致输出次数翻倍。 - 线程终止方式不安全:使用
terminate()强制杀死线程,可能导致资源泄漏,且无法保证线程正常清理。 - QThread复用问题:QThread对象只能调用一次
start(),线程结束后直接再次调用start()会失败,你当前的写法虽然没报错,但后续逻辑会出现异常。
修复方案
1. 仅绑定一次信号
把信号连接移到MainWindow的初始化方法中,避免重复绑定:
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() loadUi('wind.ui', self) self.startButton.clicked.connect(self.start_screen) self.stopButton.clicked.connect(self.stop_screen) self.screen_thread = Screenshot() # 只在初始化时绑定一次信号 self.screen_thread.any_signal.connect(self.myfunction)
2. 用标志位安全终止线程
放弃terminate(),改用布尔标志位控制线程循环,让线程自行退出:
class Screenshot(QThread): any_signal = pyqtSignal(int) def __init__(self, parent = None): super(Screenshot, self).__init__(parent) self._running = False # 线程运行标志 def run(self): self._running = True value = 1 print('process start') print(threading.active_count()) print(threading.enumerate()) while self._running: value += 1 time.sleep(1) self.any_signal.emit(value) print('process stopped gracefully') def stop(self): print('process stop') self._running = False self.wait() # 等待线程正常退出 print(self.isRunning())
3. 支持线程重复启动
QThread启动一次结束后无法再次调用start(),需重新创建实例:
def start_screen(self): if not self.screen_thread.isRunning(): # 如果线程已结束,重新创建实例并绑定信号 if self.screen_thread.isFinished(): self.screen_thread = Screenshot() self.screen_thread.any_signal.connect(self.myfunction) self.screen_thread.start()
内容的提问来源于stack exchange,提问作者Pihto
相关产品推荐
相关产品推荐

