[Python] PyQt5 QThreads persists in call stack shown by VSCode after thread quitting

Discussão em 'Python' iniciado por Stack, Março 3, 2025.

  1. Stack

    Stack Membro Participativo

    I am running this simple SignalManager class to manage running and closing some QThreads spawned by Parent. And this seems to work without a fuss in non-debugging mode. GUI uses around 480 MB and one thread adds roughly 120 MB of RAM and the memory used by the thread is freed once I hit the button responsible for closing the thread.

    What I wonder about is why in debugging mode the Dummy-N thread is considered as Running even after closing it. I use latest versions of VSCode (1.97.2) and Microsoft Python Debugger (2025.1.2025022401). Python 3.11.6, PyQt5 version 5.15.10.

    class Parent(QMainWindow, SignalManager):
    def __init__(self):
    super().__init__()
    self.signalmanager = SignalManager(self)
    # other parent class definitions

    class SignalManager:
    def __init__(self, parent):
    super().__init__()
    self.parent = parent

    def start_signal_generator(self, channel: int, connector_state: bool):
    if channel == 1:
    # Ensure the previous thread is properly finished
    if hasattr(self, "channel1_thread") and self.channel1_thread is not None:
    self.stop_signal_generator(channel)
    # Define worker thread
    self.channel1_thread = QThread()
    self.running_threads.append(self.channel1_thread)
    self.channel1_generator = SignalGenerator(self.parent, channel, connector_state)
    self.channel1_generator.moveToThread(self.channel1_thread)
    self.channel1_thread.started.connect(self.channel1_generator.run)
    self.channel1_generator.finished.connect(self.channel1_thread.quit)
    self.channel1_generator.finished.connect(self.channel1_generator.deleteLater)
    self.channel1_thread.finished.connect(self.channel1_thread.deleteLater)
    self.channel1_generator.progress.connect(self._reportProgress)
    self.parent.connector1_toggled.connect(lambda state: self.channel1_generator.update_connector_state(state))
    self.channel1_thread.start()
    else:
    logging.debug("Invalid channel number.")

    def stop_signal_generator(self, channel):
    if channel == 1 and self.channel1_thread is not None and self.channel1_generator.is_running():
    self.channel1_generator.stop()
    self.channel1_thread.quit()
    self.channel1_thread.wait()
    self.channel1_thread = None
    print("Thread for channel 1 quitted.")
    else:
    logging.debug("Invalid channel number.")

    def _reportProgress(self, channel, t, wfm):
    pass

    class SignalGenerator(QObject):
    finished = pyqtSignal()
    progress = pyqtSignal(int, object, object)

    def __init__(self, parent, *args, **kwargs):
    super().__init__()
    self.parent = parent
    self.running = True
    # Some other class instance definitions

    def run(self):
    """Long-running task of generating/updating the signal"""
    debugpy.debug_this_thread() # this is for debugging inside `QThread`s (probable culprit of persistent threads in VSCode callstack)

    while self.running:
    if not self.running:
    break
    time.sleep(1)
    self.progress.emit(1,[1,2,3],[1,2,3])

    self.finished.emit()
    self.stop()

    def stop(self):
    self.running = False

    def is_running(self):
    return self.running


    launch.json

    {
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
    {
    "name": "Python Debugger: Current File in Current Workspace with Qt",
    "type": "debugpy",
    "request": "launch",
    "program": "${workspaceFolder}/__main__.py",
    "console": "integratedTerminal",
    "cwd": "${workspaceFolder}",
    "justMyCode": false
    }
    }

    Continue reading...

Compartilhe esta Página