There are two main problems in your example:
Firstly, you are emitting a signal to stop the worker, but since the signal is cross-thread, it will be posted in the receiver's event-queue. However, the worker is running a blocking while-loop, so pending events cannot be processed. There are a few ways to work around this, but probably the simplest is to simply call the worker's stop
method directly instead of using a signal.
Secondly, you are not explicitly running an event-loop in the main thread, so cross-thread signals sent from the worker cannot be queued. More importantly, though, there is also nothing to stop the program exiting after the user presses a key - so the client and worker will be immediately garbage-collected.
Below is a re-written version of your example which fixes all the issues:
import time, sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Worker(QObject):
sgnFinished = pyqtSignal()
def __init__(self, parent):
QObject.__init__(self, parent)
self._mutex = QMutex()
self._running = True
@pyqtSlot()
def stop(self):
print 'switching while loop condition to false'
self._mutex.lock()
self._running = False
self._mutex.unlock()
def running(self):
try:
self._mutex.lock()
return self._running
finally:
self._mutex.unlock()
@pyqtSlot()
def work(self):
while self.running():
time.sleep(0.1)
print 'doing work...'
self.sgnFinished.emit()
class Client(QObject):
def __init__(self, parent):
QObject.__init__(self, parent)
self._thread = None
self._worker = None
def toggle(self, enable):
if enable:
if not self._thread:
self._thread = QThread()
self._worker = Worker(None)
self._worker.moveToThread(self._thread)
self._worker.sgnFinished.connect(self.on_worker_done)
self._thread.started.connect(self._worker.work)
self._thread.start()
else:
print 'stopping the worker object'
self._worker.stop()
@pyqtSlot()
def on_worker_done(self):
print 'workers job was interrupted manually'
self._thread.quit()
self._thread.wait()
if raw_input('
quit application [Yn]? ') != 'n':
qApp.quit()
if __name__ == '__main__':
# prevent some harmless Qt warnings
pyqtRemoveInputHook()
app = QCoreApplication(sys.argv)
client = Client(None)
def start():
client.toggle(True)
raw_input('Press something
')
client.toggle(False)
QTimer.singleShot(10, start)
sys.exit(app.exec_())
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…