2016-04-03 5 views
0

Wenn ich die Funktion ändere, die QThread in '_do_print2' im folgenden 'minimalen' Beispiel startet, bleibt mein MainWindow stehen. Zum Vergleich: Der obere Button startet den QThread ohne Probleme. Warum muss der Thread ein untergeordnetes Objekt der MainWindow-Klasse sein?Warum friert meine Qt-Anwendung ein, wenn der Thread kein untergeordnetes Objekt des Hauptthreads ist?

Im mit Python 2.7.6 und Qt 4.8.6.

from PyQt4 import QtCore, QtGui 
import sys, time 

class MainWindow(QtGui.QDialog): 
    def __init__(self): 
     super(self.__class__, self).__init__() 
     self.verticalLayout = QtGui.QVBoxLayout(self) 
     self.pushButton = QtGui.QPushButton() 
     self.pushButton2 = QtGui.QPushButton() 
     self.verticalLayout.addWidget(self.pushButton) 
     self.verticalLayout.addWidget(self.pushButton2) 
     QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self._do_print) 
     QtCore.QObject.connect(self.pushButton2, QtCore.SIGNAL('clicked()'), self._do_print2) 
    ## Working function 
    def _do_print(self): 
     self.thread = Worker(printer) 
     self.thread.start() 
    ## Function freezes the MainWindow 
    def _do_print2(self): 
     thread = Worker(printer) 
     thread.start() 


def printer(): 
    while True: 
     print "alive" 
     time.sleep(1) 

class Worker(QtCore.QThread): 
    def __init__(self, function, *args, **kwargs): 
     super(self.__class__, self).__init__() 
     self.args = args 
     self.kwargs = kwargs 
     self.function = function 

    def run(self): 
     self.function(*self.args, **self.kwargs) 
     return 

    def __del__(self): 
     self.wait() 

app = QtGui.QApplication(sys.argv) 
window = MainWindow() 
window.show() 
sys.exit(app.exec_()) 

Antwort

1

Das Skript "friert" ein, weil Sie ihm genau das gesagt haben.

In der Klasse Worker ist eine __del__-Methode definiert, die den Thread wartet (oder "einfriert", wie Sie ihn eingeben), bis die run-Methode zurückkehrt. Aber es wird natürlich nie zurückkehren, weil es eine Funktion aufruft, die eine Blockierungsschleife startet, die niemals endet. Die __del__-Methode wird aufgerufen, weil Sie keinen Verweis auf den Thread behalten haben, und so wird eine Müllsammlung durchgeführt, sobald die Methode _do_print2() zurückkehrt (d. H. Unmittelbar nach dem Start des Threads).

Beachten Sie, dass der erste Thread kein Kind des Hauptfensters ist - es ist nur ein Instanzattribut (was es am Leben hält). Wenn Sie die __del__-Methode entfernen, stürzt das Starten des zweiten Threads wahrscheinlich das Programm ab, da dann nichts den vorgehenden C++ - Thread vorzeitig beendet.

+0

Also der Garbage Collector möchte den Worker Thread entfernen, ist Teil des ersten Threads (in dem 'Fenster' läuft), muss aber auf seine Entfernung warten und blockiert daher seinen Thread. Recht? –

+0

@ JohnH.K. Nein, es ist der 'wait()' des Threads, der sofortiges Löschen verhindert. Siehe den letzten Satz meiner Antwort. – ekhumoro

+0

Ich meine die Funktion wait() mit 'muss warten'. Diese Funktion befindet sich jedoch im Worker-Objekt und nicht im Hauptfensterobjekt. Der Haupt-Thread möchte die self .__del__-Funktion des Arbeiters verwenden - richtig? –

Verwandte Themen