私はいくつかのマルチスレッドをやっています。私は別のQThread
に送ってwork
メソッドを持つワーカークラスを持っています。 work
メソッドは内部に条件付きwhileループを持ちます。ワーカーオブジェクトに信号を送信して停止させたい(_running
の条件をfalseに変更したい)。これにより、whileループが終了し、作業者オブジェクト(作業者のスレッドの終了スロットに接続されている)から終了信号が送信されます。PyQt:オブジェクトがwhileループを実行しているスレッドに停止信号を送るには?
信号を介してfalse条件がワーカーオブジェクトに送信されますが、受信されません。これは、whileループがそのスレッドのイベントループをブロックするためと考えられます。たとえ私がQCoreApplication.processEvents()
をwhileループの中に入れても、何も起こりません。問題はどこだ?なぜシグナルが処理されないのですか? (ワーカーの停止スロットにあるprint文は決して実行されませんが、奇妙なことは、スレッドが間違った方法で停止しているように見えることです)。ここ
コードされる:
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._running = True
@pyqtSlot()
def stop():
print 'stop signal received, switching while loop condition to false'
self._running = False
@pyqtSlot()
def work(self):
while self._running: #this blocks the thread, if changed to an if clause, thread finishes as expected!
QCoreApplication.processEvents() #this doesn't help!
time.sleep(0.1)
print 'doing work...'
#do some cleanup here, then signal the worker is done
self.sgnFinished.emit()
class Client(QObject):
sgnStop = pyqtSignal()
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.sgnStop.connect(self._worker.stop)
self._thread.started.connect(self._worker.work)
self._thread.start()
else:
print 'sending stop signal to the worker object'
self.sgnStop.emit() #send a queuedconnection type signal to the worker, because its in another thread
@pyqtSlot()
def on_worker_done(self):
print 'workers job was interrupted manually'
self._thread.quit()
#self._thread.wait() not sure this is neccessary
if __name__ == '__main__':
app = QCoreApplication(sys.argv)
client = Client(None)
client.toggle(True)
raw_input('Press something')
client.toggle(False)
http://stackoverflow.com/questions/32952474/non-blocking-worker-interrupt-file-copy – dtech
私は理解していない解決策を見つけました。停止信号接続宣言をこれに置き換えると(ラムダ式としてハンドラを追加する)、問題を解決します:self.sgnStop.connect(lambda:self._worker.stop()) – U2ros
これはうまくいきません。作業メソッドから起動されるため、on_worker_doneはクライアント上で呼び出されません。 – U2ros