2016-04-03 47 views
0

當我在下面的'minimal'示例中將啓動QThread的函數更改爲'_do_print2'時,我的MainWindow凍結。爲了比較,上面的按鈕將啓動QThread,沒有任何問題。爲什麼線程是MainWindow類的子對象?如果線程不是主線程的子對象,爲什麼我的Qt應用程序會凍結?

我使用Python 2.7.6和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_()) 

回答

1

該腳本「凍結」,因爲你告訴它做到這一點。

Worker類有一個定義的__del__方法,它使線程等待(或「凍結」,就像你放置它一樣),直到run方法返回。但是它當然永遠不會返回,因爲它調用了一個啓動永不終止的阻塞循環的函數。調用__del__方法是因爲您沒有保留對該線程的引用,因此只要_do_print2()方法返回(即在線程啓動後立即),它就會被垃圾回收。

請注意,第一個線程不是主窗口的子項 - 它只是一個實例屬性(這是它保持活動狀態)。如果刪除了__del__方法,則啓動第二個線程可能會使程序崩潰,因爲沒有任何事情可以阻止基礎C++線程被過早刪除。

+0

所以垃圾收集器想要刪除工作線程,是第一個線程('窗口'在其中運行)的一部分,但必須等待其刪除,並因此阻止其線程。對? –

+0

@ JohnH.K。不,它是線程的'wait()',可以防止立即刪除。看到我答案的最後一句話。 – ekhumoro

+0

我的意思是功能wait()'必須等待'。但是這個函數在工作對象中,而不在主窗口對象中。主線程想要使用worker的self .__ del__函數 - 正確嗎? –

相關問題