pkaramol
pkaramol

Reputation: 19322

PySide: QThread event handling

I have been researching the following issue on PySide threading, but I have found very little documentation so here goes a long post on my findings hoping for some concise feedback about how it goes. Supposing we are building a multi-threaded GUI application that invokes some linux processes. We will be using QThread class to call a QProcess from within with the objective of having the application running multiple processess simultaneously when it is ready (in different threads)

I am using just a QThread Class and starting through the QApplication main loop

Case 1: - We connect the thread termination signal to another function of the same class that calls self.exit (so that the thread class exits) - No call to self.exec_() as instructed in the official documentation of PySide http://tinyurl.com/qh7cooa

#!/usr/bin/python3.2
from PySide import QtGui
from PySide import QtCore
import sys, random

class ProcThread(QtCore.QThread):

    def __init__(self, parent=None):
        super(ProcThread, self).__init__(parent)

    def run(self):
        try:
            self.qproc = QtCore.QProcess()
            self.finished.connect(self.threadFinished)
            filename = "/home/user1/Desktop/fileno"+str(random.randint(1, 10000))+".txt"
            self.qproc.start("touch", [filename])       
        except Exception as error:
            print(str(error))
            raise(error)

    #self.exec_()

    def threadFinished(self):
        print("Thread has finished")
        self.qproc.close()

app = QtGui.QApplication(sys.argv) 
procthread = ProcThread()
procthread.start()
app.exec_()

RESULT: The thread termination is caught (message "Thread has finished" gets printed), the process does run (file is created) but the application DOES NOT EXIT

Case 2: Same as before, but now also calling self._exec() (uncommenting the relevant line in previous code snippet) RESULT: The thread termination is NOT caught, the process does run (file is created) and once again the application DOES NOT EXIT (remains as a background job) after Ctrl+Z / have to kill it explicitly

Case 3: Now connecting the signal emmitted when the QProcess terminates through self.qproc.finished.connect(self.threadFinished). No call to self.exec_()

only citing code between try-except - #self.exec_() remains commented
self.qproc = QtCore.QProcess()
self.qproc.finished.connect(self.threadFinished)
filename = "/home/pantelis/Desktop/fileno" + str(random.randint(1, 10000)) + ".txt"
self.qproc.start("touch", [filename])

RESULT: As in Case 2 - The thread termination is NOT caught, the process does run (file is created) and once again the application DOES NOT EXIT

Case 4: As in Case 1, but now adding the following line in threadFinished self.exit() RESULT: As in Case 2 - The thread termination is NOT caught, the process does run (file is created) and once again the application DOES NOT EXIT

Case 5: As in Case 4, just uncommenting the self.exec_() RESULTS: Thread termination IS CAUGHT (message "Thread has finished" gets printed), file IS created and once again the application DOES NOT EXIT

Cases 6, 7, 8: Added self.qproc.close() / self.qproc.terminate() / self.qproc.kill() in threadFinished to explicitly terminate the QProcess from the specific function RESULT: As in Case 5

One could also try different alternatives, such as linking the self.terminated signal of QThread to threadFinished and so on. Some very rough questions although I guess is a complex issue: - Why although formal documentation states that call to QThread's exec_() function is necessary for the thread to start event handling, this seems to be occurring without a call to the specific functions - In some cases thread termination is caught / processed by threadFinished and in some it is not - most importantly: why doesn't the application terminate? (I have also tried app = QtCore.QCoreApplication(sys.argv))

Upvotes: 0

Views: 1442

Answers (1)

MadeOfAir
MadeOfAir

Reputation: 3183

Just call app.quit() in your threadFinished handler, and if you have visible widgets, hide() and destroy() the main window, this should take care of destroying all children.

Upvotes: 2

Related Questions