2017-10-01 8 views
1

QThreadの中にWorkerを実行して、PyQt5とPython 3.5でマルチスレッドを実装しています。次のサンプルでは、​​thread2_worker(セカンダリスレッド内で実行され、thread3_workerを作成し、thread3_worker.finished信号をthread3_worker_finished()に接続して実行します)。PyQt - 異なるスレッドで作成されたオブジェクトのシグナルが機能しません

thread3_workerを実行すると、そのスレッド内からfinishedが出力されますが、接続できません。私の推測では、thread3_workerが作成されているかメインスレッドに接続されていないことが関係していますが、何らかの説明を歓迎します。

import time 
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot, QCoreApplication 


class Worker(QObject): 
    # Generic worker. 
    finished = pyqtSignal() 

    def __init__(self, func): 
     super().__init__() 
     self.func = func 

    def run(self): 
     self.func() 
     self.finished.emit() 


def thread_factory(func): 
    # Creates a Worker, a QThread and moves the Worker inside the QThread. 
    worker = Worker(func) 
    thread = QThread() 
    worker.moveToThread(thread) 
    thread.started.connect(worker.run) 

    # Provision graceful termination. 
    worker.finished.connect(thread.quit) 
    worker.finished.connect(worker.deleteLater) 
    thread.finished.connect(thread.deleteLater) 

    return worker, thread 


def wait(): 
    print("thread3:\t{}".format(QThread.currentThread())) 
    time.sleep(3) 


# finished signal of thread3_worker is never received. 
@pyqtSlot() 
def thread3_worker_finished(): 
    QCoreApplication.exit() 


def create_thread3(): 
    print("thread2:\t{}".format(QThread.currentThread())) 
    global thread3_worker, thread3 
    # thread3_worker runs inside thread3, and all it does is call wait(). 
    thread3_worker, thread3 = thread_factory(wait) 
    thread3_worker.finished.connect(thread3_worker_finished) # FIXME Doesn't work. 
    thread3.start() 


app = QCoreApplication([]) 
print("Main thread:\t{}".format(QThread.currentThread())) 
thread3_worker, thread3 = None, None 
# thread2_worker runs inside thread2, and creates and runs thread3_worker. 
thread2_worker, thread2 = thread_factory(create_thread3) 
thread2.start() 
app.exec_() 

答えて

0

クロススレッド信号にはイベントループが必要です。 thread_factory関数は、作業者のfinished信号をスレッドのquitスロットに接続します。 quitスロットはスレッドにイベントループを終了するように要求します。

スレッド3の開始後、worker2が終了し、thread2が終了します。その後、worker3の信号finishedが発行されると、それを処理できるイベントループの実行がなくなります。行worker.finished.connect(thread.quit)をコメントアウトすると、あなたの例がうまくいくはずです。

+0

実際、 'worker.finished.connect(thread.quit)'をコメントアウトすることで修正されました。専門知識を共有していただきありがとうございます。私は各QThreadに独自のイベントループがあると思っていました。 – R01k

+1

@ R01k。各スレッド*は独自のイベントループを持っています。しかし、worker3はthread2のイベントループを必要とします(シグナルはスレッド間で発行されるためです)。 – ekhumoro

+0

スレッドイベントループはワーカーが終了した後も継続するので、 'thread.deleteLater()'はスレッドを最終的に削除しますか? – R01k

関連する問題