GuillaumeA
GuillaumeA

Reputation: 3545

QThread exception management and thread race

I have a GUI (PySide) application that uses QThread. I have a signal in my QThread that is emitted when an exception occurs so that I can handle the exception in the main thread. However, the rest of the function starting the thread is still executed. I tried the wait function to block the execution but it does not work. Here is my implementation:

QThread daughter

class LongTaskThread(QtCore.QThread):
    task_finished = QtCore.Signal()
    task_failed = QtCore.Signal(Exception)

    def __init__(self, allow_log=True, test_mode=False, parent=None):
        QtCore.QThread.__init__(self, parent)

    def run(self):
        self.task_failed.emit(Exception())

    def wait_with_gui_refresh(self):
        while self.isRunning():
            time.sleep(0.1)
            if not self.test_mode:
                QtGui.QApplication.processEvents()

Main thread

def test():
   my_thread = LongTaskThread()
   my_thread.task_finished.connect(on_finished)
   my_thread.task_failed.connect(on_failed)
   my_thread.start()
   # my_thread.wait()    <---- tentative 1
   # my_thread.wait_with_gui_refresh()    <---- tentative 2
   print('bla bla bla bla')

def on_finished)():
   pass

def on_failed(err):
  raise err

I expected that the print would never been hit, but whether I use the wait function or the wait_with_gui_refresh function, or nothing, the print is always printed.

How to stop the test function when an exception is raised inside the QThread ?

Upvotes: 3

Views: 2914

Answers (1)

ekhumoro
ekhumoro

Reputation: 120718

In your test function, the sequence of events is this:

  1. The thread starts
  2. The thread's run method is called
  3. The task_failed signal is emitted asynchronously (i.e. it's posted to the receiver's event queue)
  4. The thread's run method returns
  5. If the thread's wait method is called here, it will return True immediately because there is nothing to wait for (i.e. run has already returned)
  6. A message is printed, and test returns
  7. Control returns to the event-loop, and the task_failed signal is processed
  8. An exception is raised in on_failed

It's hard to see anything to object to here. Presumably, you don't want to block the gui whilst the worker thread is running, so it makes perfect sense to process any exceptions aynchronously. But for that to happen, control must return to the event-loop of the main thread - which means the test function must return immediately. If you want to run some code after the thread starts, connect a slot to its started signal.

Upvotes: 4

Related Questions