@Hellstorm:
Was Du beschreibst, funktioniert mit Signal/Slots in Richtung Mainthread(Signal)-->Subthread(Slot) nur dann, wenn der Thread bzw. die Aufgaben selbst ereignisgesteuert sind, hier mal ein Beispiel:
Code: Alles auswählen
from PyQt4 import QtCore
class Task(QtCore.QObject):
question = QtCore.pyqtSignal(str)
def start(self):
output(QtCore.QThread.currentThreadId(), 'task-start')
self.question.emit('How do you feel?')
def process_answer(self, data):
output(QtCore.QThread.currentThreadId(), 'task-process_answer')
output('Subthread reads:', data)
class EventThread(QtCore.QThread):
def run(self):
output(QtCore.QThread.currentThreadId(), 'thread-run')
self.exec_()
class Frontend(QtCore.QObject):
answer = QtCore.pyqtSignal(str)
start = QtCore.pyqtSignal()
def __init__(self, parent=None):
QtCore.QObject.__init__(self, parent)
output(QtCore.QThread.currentThreadId(), 'frontend-init')
def process_question(self, data):
output(QtCore.QThread.currentThreadId(), 'frontend-process_question')
output('question from thread:', data)
self.answer.emit('Good!') # input goes here
def _output():
m = QtCore.QMutex()
def wrapped(*it):
m.lock()
print ' '.join(str(i) for i in it)
m.unlock()
return wrapped
output = _output()
if __name__ == '__main__':
app = QtCore.QCoreApplication([])
# some frontend, e.g. a GUI
frontend = Frontend()
thread = EventThread()
# some event driven task for the thread
task = Task()
task.moveToThread(thread)
# connect question/answer ping pong between frontend and the task
task.question.connect(frontend.process_question)
frontend.answer.connect(task.process_answer)
# start the thread
# NOTE: task should start AFTER the thread's event loop is running
# otherwise early signals get lost
thread.started.connect(frontend.start)
frontend.start.connect(task.start)
thread.start()
# tier down all event loops
QtCore.QTimer.singleShot(100, lambda: all([thread.exit(), thread.wait(), app.exit()]))
app.exec_()
Wie sieht denn Deine Prozesslogik im Thread aus? Dein Beispiel hat keinerlei Objekte im Subthreadkontext, welche die Slots liefern könnten. In der Tat musst Du einen Slot erstellen, nur sehe ich kein Objekt, über welches Du das machen könntest (siehe hierzu `Task` in meinem Bsp.) Beachte, dass Du nur innerhalb von `run()` im Subthread bist, alles andere, z.B. ein zusätzlicher Slot am Threadobjekt liegen im Mainthread.
Kann es sein, dass Du in `run()` einfach an der Stelle des Signals die Verarbeitung anhalten willst bis die Antwort vorliegt und dann entsprechend weitarbeiten willst? Das ginge in der Tat mit einem Slot am Threadobjekt, welcher Daten über einen Lock dem Thread zur Verfügung stellt:
Code: Alles auswählen
from PyQt4 import QtCore
from contextlib import contextmanager
class MyThread(QtCore.QThread):
question = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
self.data = ''
self.mutex = QtCore.QMutex()
@contextmanager
def lock(self):
self.mutex.lock()
yield
self.mutex.unlock()
def run(self):
print QtCore.QThread.currentThreadId(), 'thread-run'
print 'wait for slot execution...'
self.question.emit('Wots going on?') # thread pauses here
print '...thread goes on'
with self.lock():
print self.data
def process_answer(self, data):
print QtCore.QThread.currentThreadId(), 'thread-process_answer'
with self.lock():
self.data = data
class Frontend(QtCore.QObject):
answer = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
QtCore.QObject.__init__(self, parent)
print QtCore.QThread.currentThreadId(), 'main-init'
def process_question(self, data):
print QtCore.QThread.currentThreadId(), 'main-process_question'
print data
self.answer.emit('Nothing!')
if __name__ == '__main__':
app = QtCore.QCoreApplication([])
frontend = Frontend()
thread = MyThread()
thread.question.connect(frontend.process_question, QtCore.Qt.BlockingQueuedConnection)
frontend.answer.connect(thread.process_answer)
thread.start()
QtCore.QTimer.singleShot(100, lambda: app.exit())
app.exec_()
Dieses Bsp. kommt ohne Ereignisschleife im Thread aus. Ob der Lock nötig ist, hängt vom Datentypen und den Zugriffen ab. Alternativ zu Slot + Lock könnte man auch auf `Queue` aus dem threading-Modul zurückgreifen.