Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. [PySide6] Slot Executed in Signal's Thread Even With Auto & QueuedConnection
Forum Updated to NodeBB v4.3 + New Features

[PySide6] Slot Executed in Signal's Thread Even With Auto & QueuedConnection

Scheduled Pinned Locked Moved Solved Qt for Python
13 Posts 4 Posters 1.0k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F friedemannkleint
    21 Jan 2025, 15:40

    The correct way to implement threads is to overwrite QThread.run() to do the work. We also recommend using the @Slot decorator. Consider:

    import sys
    
    from PySide6.QtCore import QObject, Signal, QThread, Qt, Slot
    from PySide6.QtWidgets import QMainWindow, QApplication
    
    
    class Worker(QThread):
        update = Signal()
    
        def run(self):
            print(f"worker: {QThread.currentThread().objectName()}")
            self.update.emit()
    
    
    class Window(QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            self._worker = Worker()
            self._worker.setObjectName('test thread')
            self._worker.update.connect(self.update)
            self._worker.start()
    
        def closeEvent(self, e):
            self._worker.wait()
            e.accept()
    
        @Slot()
        def update(self):
            print(f"window: {QThread.currentThread().objectName()}")
    
    
    if __name__ == '__main__':
        app = QApplication()
        w = Window()
        w.show()
        sys.exit(app.exec())
    
    P Online
    P Online
    Pl45m4
    wrote on 21 Jan 2025, 19:02 last edited by
    #4

    @friedemannkleint said in [PySide6] Slot Executed in Signal's Thread Even With Auto & QueuedConnection:

    The correct way to implement threads is to overwrite QThread.run() to do the work.

    Why is there only one correct approach?!
    Shouldn't the worker thread approach work the same (as also when using C++)?

    Here in this topic the worker approach seems to function correctly (besides the mistakes OP made there).


    If debugging is the process of removing software bugs, then programming must be the process of putting them in.

    ~E. W. Dijkstra

    T 1 Reply Last reply 21 Jan 2025, 20:17
    2
    • P Pl45m4
      21 Jan 2025, 19:02

      @friedemannkleint said in [PySide6] Slot Executed in Signal's Thread Even With Auto & QueuedConnection:

      The correct way to implement threads is to overwrite QThread.run() to do the work.

      Why is there only one correct approach?!
      Shouldn't the worker thread approach work the same (as also when using C++)?

      Here in this topic the worker approach seems to function correctly (besides the mistakes OP made there).

      T Offline
      T Offline
      thinkinmachine
      wrote on 21 Jan 2025, 20:17 last edited by
      #5

      @Pl45m4

      Thanks for the reply! I did read that post. I’m really confused to see that one works because it’s almost the same as mine. Do you have any idea why this is happening?

      1 Reply Last reply
      0
      • T Offline
        T Offline
        thinkinmachine
        wrote on 21 Jan 2025, 20:55 last edited by thinkinmachine
        #6

        It's reported to Qt Bug Tracker: https://bugreports.qt.io/browse/PYSIDE-2990

        Update: tested cpp equivalent version and it worked fine. It should be a PySide issue.

        1 Reply Last reply
        2
        • F Offline
          F Offline
          friedemannkleint
          wrote on 22 Jan 2025, 07:24 last edited by friedemannkleint
          #7

          Please don't use that technique of connecting a worker to the QThread.start() signal. It leaks a thread hanging in its exec() function since that is called by the default implementation of run(), plus the signal execution is blocked by the work.

          T 1 Reply Last reply 22 Jan 2025, 16:48
          1
          • T thinkinmachine has marked this topic as solved on 22 Jan 2025, 16:45
          • F friedemannkleint
            22 Jan 2025, 07:24

            Please don't use that technique of connecting a worker to the QThread.start() signal. It leaks a thread hanging in its exec() function since that is called by the default implementation of run(), plus the signal execution is blocked by the work.

            T Offline
            T Offline
            thinkinmachine
            wrote on 22 Jan 2025, 16:48 last edited by thinkinmachine
            #8

            @friedemannkleint
            Thank you so much. I didn't notice update would be a issue.

            However I found another issue. When I use PyCharm's debugger to run the code the thread of worker becomes main thread again. It might have to do with debugger settings.

            Update: When the main thread is blocked by breakpoint, the child threads are all blocked as well. This ONLY happens with PyCharm debugging.

            F 1 Reply Last reply 22 Jan 2025, 23:35
            1
            • T thinkinmachine
              22 Jan 2025, 16:48

              @friedemannkleint
              Thank you so much. I didn't notice update would be a issue.

              However I found another issue. When I use PyCharm's debugger to run the code the thread of worker becomes main thread again. It might have to do with debugger settings.

              Update: When the main thread is blocked by breakpoint, the child threads are all blocked as well. This ONLY happens with PyCharm debugging.

              F Offline
              F Offline
              FlowOverNestedThreads
              wrote on 22 Jan 2025, 23:35 last edited by FlowOverNestedThreads
              #9

              @thinkinmachine can confirm (dear lord, how have you even pinpointed the reason?), also related

              T 1 Reply Last reply 24 Jan 2025, 00:10
              0
              • T Offline
                T Offline
                thinkinmachine
                wrote on 23 Jan 2025, 06:13 last edited by thinkinmachine
                #10

                Also, it doesn't work if lambda is used. Probably because Qt doesn't know which thread the lambda function should be in.

                self._worker.update.connect(lambda: self.slotUpdate())
                
                1 Reply Last reply
                0
                • T thinkinmachine
                  21 Jan 2025, 06:16

                  I'm having trouble with signal & slot in different threads. The slot is always executed in the signal caller's thread, even with explicit QueuedConnection . Below is the minimal example.

                  import sys
                  
                  from PySide6.QtCore import QObject, Signal, QThread, Qt
                  from PySide6.QtWidgets import QMainWindow, QApplication
                  
                  
                  class Worker(QObject):
                      update = Signal()
                  
                      def run(self):
                          print(f"worker: {QThread.currentThread().objectName()}")
                          self.update.emit()
                  
                  
                  class Window(QMainWindow):
                      def __init__(self, parent=None):
                          super().__init__(parent)
                          worker = Worker()
                          thread = QThread()
                          thread.setObjectName('test thread')
                          worker.moveToThread(thread)
                          thread.started.connect(worker.run)
                          worker.update.connect(self.update)
                          thread.start()
                  
                      def update(self):
                          print(f"window: {QThread.currentThread().objectName()}")
                  
                  
                  if __name__ == '__main__':
                      app = QApplication()
                      w = Window()
                      w.show()
                      sys.exit(app.exec())
                  

                  The output of this minimal example is

                  worker: Qt mainThread
                  window: test thread
                  

                  Seems like the slot is always executed in signal caller's thread, because the thread of thread.start is main thread, and the thread of worker.update is test thread. The result is the same after I add QueuedConnection explicitly.

                  I've read the document of QThread several times, including this one, and it seems like I'm using threads in the correct way. Please correct me if I'm wrong.

                  My PySide version is 6.8.1. Any help would be greatly appreciated.

                  P Online
                  P Online
                  Pl45m4
                  wrote on 23 Jan 2025, 12:13 last edited by
                  #11

                  @thinkinmachine said in [PySide6] Slot Executed in Signal's Thread Even With Auto & QueuedConnection:

                  Probably because Qt doesn't know

                  It's not a Qt thing I would say, rather than Python-related.
                  I'm not the best at Python, but AFAIK there is not "context" in Python lambdas (correct me if I'm wrong).
                  In C++ the Qt Signal-Slot lambda is executed in the "context" (if any) object's thread, or the receiving one.
                  Like

                  // ------------------------------------
                  Worker w;
                  int result = 42;
                  emit w.workFinished(result);
                  // ------------------------------------
                  connect(&w, &Worker::workFinished, this, [=](int res) {
                         int result = res + 123;
                         doSomethingWith(result);
                  });
                  
                  // ------------------------------------
                  

                  If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                  ~E. W. Dijkstra

                  T 1 Reply Last reply 24 Jan 2025, 00:11
                  1
                  • F FlowOverNestedThreads
                    22 Jan 2025, 23:35

                    @thinkinmachine can confirm (dear lord, how have you even pinpointed the reason?), also related

                    T Offline
                    T Offline
                    thinkinmachine
                    wrote on 24 Jan 2025, 00:10 last edited by
                    #12

                    @FlowOverNestedThreads

                    I reported this bug to JetBrain PyCharm team (here). Hopefully they can help figure out what's going on. Thanks for providing stackoverflow link.

                    1 Reply Last reply
                    0
                    • P Pl45m4
                      23 Jan 2025, 12:13

                      @thinkinmachine said in [PySide6] Slot Executed in Signal's Thread Even With Auto & QueuedConnection:

                      Probably because Qt doesn't know

                      It's not a Qt thing I would say, rather than Python-related.
                      I'm not the best at Python, but AFAIK there is not "context" in Python lambdas (correct me if I'm wrong).
                      In C++ the Qt Signal-Slot lambda is executed in the "context" (if any) object's thread, or the receiving one.
                      Like

                      // ------------------------------------
                      Worker w;
                      int result = 42;
                      emit w.workFinished(result);
                      // ------------------------------------
                      connect(&w, &Worker::workFinished, this, [=](int res) {
                             int result = res + 123;
                             doSomethingWith(result);
                      });
                      
                      // ------------------------------------
                      
                      T Offline
                      T Offline
                      thinkinmachine
                      wrote on 24 Jan 2025, 00:11 last edited by
                      #13

                      @Pl45m4

                      Thanks for your explanation! I'll keep you posted if I find out something new on this topic.

                      1 Reply Last reply
                      0

                      13/13

                      24 Jan 2025, 00:11

                      • Login

                      • Login or register to search.
                      13 out of 13
                      • First post
                        13/13
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved