0

The QThread seems to be running in the background always even after the Thread object is deleted. I took this example to demonstrate the problem I'm facing. The thread is in active state all the time [When it's Running, Finished and Deleted]

Refer the code below

from PyQt4.QtCore import QThread, QTimer,QObject, pyqtSignal, pyqtSlot, Qt
from PyQt4.QtGui import QApplication, QLabel, QWidget, QGridLayout
import sys
import time
import threading
import sip

def activeThreads():            
    currentThread = threading.current_thread()
    print("Current Thread=",currentThread)
    n = 0
    for td in threading.enumerate():
        if td is not currentThread:
            print("Thread = ",td)

class Worker(QObject):
    finished = pyqtSignal()
    intReady = pyqtSignal(int)

    def __init__(self, maxCount):
        super().__init__()
        self.maxCount=maxCount

    @pyqtSlot()
    def procCounter(self): # A slot takes no params
        for i in range(1, self.maxCount):
            time.sleep(0.5)
            self.intReady.emit(i)
        print("Called from worker thread")
        activeThreads()
        self.finished.emit()

class Form(QWidget):
    def __init__(self):
        super().__init__()
        self.label = QLabel("0")

        # 1 - create Worker and Thread inside the Form
        self.obj = Worker(6)  # no parent!
        self.thread = QThread()  # no parent!

        # 2 - Connect Worker`s Signals to Form method slots to post data.
        self.obj.intReady.connect(self.onIntReady)

        # 3 - Move the Worker object to the Thread object
        self.obj.moveToThread(self.thread)

        # 4 - Connect Worker Signals to the Thread slots
        #self.obj.finished.connect(self.thread.quit)
        self.obj.finished.connect(self.quitThread)

        # 5 - Connect Thread started signal to Worker operational slot method
        self.thread.started.connect(self.obj.procCounter)

        # 6 - Start the thread
        self.thread.start()

        # 7 - Start the form
        self.initUI()

    def quitThread(self):
        self.thread.quit()
        #self.obj.deleteLater()
        self.checkThread()

    def checkThread(self):
        try:
            self.thread.objectName()
        except RuntimeError as err:
            print("-----------------------------------------------------------")
            print("Error=",err)
            print("After Worker thread object deleted")
            activeThreads()
            return
        if self.thread.isRunning():
            #print("Still running")
            QTimer.singleShot(1, self.checkThread)
            #activeThreads()
        if self.thread.isFinished():
            print("-----------------------------------------------------------")
            print("After worker thread finished")
            activeThreads()
            self.obj.deleteLater()
            self.thread.deleteLater()
            QTimer.singleShot(1, self.checkThread)

    def initUI(self):
        grid = QGridLayout()
        self.setLayout(grid)
        grid.addWidget(self.label,0,0)

        self.move(300, 150)
        self.setWindowTitle('thread test')
        self.show()

    def onIntReady(self, i):
        self.label.setText("{}".format(i))

app = QApplication(sys.argv)

form = Form()

sys.exit(app.exec_())

Here's the output

Called from worker thread  
Current Thread= <_DummyThread(Dummy-1,started daemon 6692)  
Thread =  <_MainThread(MainThread, started 10204)
-----------------------------------------------------------  
After worker thread finished  
Current Thread= <_MainThread(MainThread,started 10204)>  
Thread =  <_DummyThread(Dummy-1, started daemon 6692)>
-----------------------------------------------------------  
Error= wrapped C/C++ object of type QThread has been deleted  
After Worker thread object deleted  
Current Thread= <_MainThread(MainThread, started 10204) 
Thread =  <_DummyThread(Dummy-1, started daemon 6692)>

Am I using it in the right way?. Please let me know if I miss something here.

P.S: It can be understood that no matter whether we set the object name or not, Python will name it as "Dummy-1,2" since it was not created using threading module.

Community
  • 1
  • 1
TFA
  • 81
  • 10
  • The `activeThread()` calls always raise an `AssertionError` for me. There's probably some obscure system-specific garbage-collection issue somewhere. Don't mix `QThread` and `threading` - stick to one or the other. – ekhumoro Mar 24 '17 at 17:19
  • Yes @ekhumoro. I always make it a practice to stick to QThread when doing operations in the UI. However when the user quits our application built in Python, we check for active Python and PyQt threads and terminate them on app quit. I hope there's some issue. Can you please try to run in a different environment? – TFA Mar 27 '17 at 08:38
  • But clearly, the worker thread *does* terminate (i.e. it emits the `finished` signal). Also, the underlying C++ object has already been successfully deleted. If you hadn't used the `threading` module, those dummy python thread objects would never have been created. This looks like a non-problem of your own making. – ekhumoro Mar 27 '17 at 17:57

0 Answers0