Reputation: 19322
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_()
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
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