关闭PyQt5 QDialog时出现QThread: Destroyed while thread is still running报错如何解决
问题根因
你已经将QThread绑定为NextWindow的实例属性,且指定了父对象,但问题出在关闭NextWindow时,你没有主动终止仍在运行的子线程,窗口销毁时会直接回收作为子对象的QThread实例,触发报错。尤其是当哈希任务还没跑完就关闭窗口时,100%会复现这个问题。
修复步骤
1. 给Worker加终止标记,支持中途停止任务
在Worker类里加终止flag和对应的停止方法,让哈希循环可以主动中断:
class Worker(qtc.QObject): hashed = qtc.pyqtSignal(str, str) # 新增终止标记 _is_running = True @qtc.pyqtSlot(str) def hash_directory(self, root): self._is_running = True hash_gen = recursive_hashes(Path(root)) for path, sha1_hash in hash_gen: # 每次循环先判断是否要停止 if not self._is_running: break self.hashed.emit(path, sha1_hash) @qtc.pyqtSlot() def stop(self): self._is_running = False
2. 重写NextWindow的closeEvent,关闭前先清理线程
在NextWindow类里新增关闭事件处理逻辑,主动停止Worker任务,等待线程完全退出后再销毁窗口:
class NextWindow(qtw.QDialog): # 原有代码保持不变,新增以下方法 def closeEvent(self, event): # 停止worker的哈希任务 self.worker.stop() # 退出线程并等待线程完全结束 self.worker_thread.quit() self.worker_thread.wait() # 接受关闭事件 event.accept()
3. 可选优化:增加关闭确认
如果不想用户误操作中断正在运行的任务,可以在关闭时增加二次确认逻辑:
def closeEvent(self, event): if self.worker_thread.isRunning() and self.worker._is_running: reply = qtw.QMessageBox.question(self, '确认关闭', '哈希任务正在运行,确定要终止并关闭窗口吗?', qtw.QMessageBox.Yes | qtw.QMessageBox.No, qtw.QMessageBox.No) if reply == qtw.QMessageBox.No: event.ignore() return # 原有清理线程逻辑 self.worker.stop() self.worker_thread.quit() self.worker_thread.wait() event.accept()
注意事项
不要直接调用QThread.terminate()强制杀死线程,该方法在Qt中属于不安全操作,可能导致资源泄漏或者程序崩溃,优先使用主动标记退出+quit()+wait()的组合方案。如果存在超大文件读取的长时间阻塞场景,可以把文件读取块的大小调小,或者在读取循环里也加入终止判断,提升停止操作的响应速度。
内容的提问来源于stack exchange,提问作者Roy Dai
相关产品推荐
相关产品推荐

