中断 QThread 睡眠

Interrupting QThread sleep

我想知道如何暂停 QThread 然后在收到信号时恢复。我已经阅读并知道我可以做这样的事情:

def run(self):
    ...
    self.ready=False
    while not self.ready:
        self.sleep(1)
    ...
...
@QtCore.Slot()
def set_ready(self):
    self.ready = True

但是,我想做的是避免线程中的轮询。我不想将睡眠设置为很短的时间并继续检查。我想去睡觉,直到我从主线程收到继续的信号。

我在我的线程中做的是这样的:

(pseudo code)
with open file:
    read a block of data
    while data:
        sendThread = send the block via UDP
        read the next block of data
        while not ready or sendThread.isRunning:
            sleep(0.1)

在我的主线程中,我设置了一个 QtNetwork.QUdpSocket 来将 readyRead 连接到一个方法来处理传入的数据报并对其进行解码。当它得到我正在等待的响应时,它会向 set_ready 槽发送一个信号,告诉线程发送另一个数据报。我并不总是知道其他系统需要多长时间才能响应,但我可能会有 30 秒左右的超时值。

有没有办法中断线程的休眠?所以我可以这样做:

sleep(30)
if not ready:
    Timeout occurred stop processing
else:
    Continue processing.

您可以使用 QThreads 工作模式 轻松完成此操作。 QThread 文档中有一个 example。确切的代码会有所不同,具体取决于您使用的是 PyQt 还是 PySide(看起来您使用的是示例中的 PySide)。

PyQt 相比,PySide 的一个显着问题是 they didn't wrap QtCore.Q_ARG,因此在 PyQt 中,您通常可以使用 QMetaObject.invokeMethod 调用插槽(带参数)在主线程的 Worker 对象上,你不能直接在 PySide 中这样做,必须创建一个 dummy 信号(即.Main.send_signal) 以连接到 worker 上的插槽,以便您可以从主线程调用它。

import time
import sys
from PySide import QtCore, QtGui


class Worker(QtCore.QObject):

    send_signal = QtCore.Signal(str) # using PySide
    # QtCore.pyqtSignal(str) ## using PyQt

    # @QtCore.pyqtSlot(str)
    @QtCore.Slot(str)
    def receive_slot(self, data):
        # data could be a filepath
        # open file
        # ... do stuff
        # close file
        QtCore.QThread.sleep(1) # to simulate doing stuff
        self.send_signal.emit(data + ' success')


class Main(QtGui.QWidget):

    send_signal = QtCore.Signal(str)

    def __init__(self):
        super(Main, self).__init__()
        self.worker = Worker()
        self.thread = QtCore.QThread(self)
        self.worker.moveToThread(self.thread)
        self.worker.send_signal.connect(self.receive_slot)
        self.send_signal.connect(self.worker.receive_slot)
        self.thread.start()
        self.send_signal.emit('Start')

    @QtCore.Slot(str)
    def receive_slot(self, data):
        print 'Main: {}'.format(data)
        self.send_signal.emit('Message {}'.format(time.time()))


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    window = Main()
    window.show()
    app.exec_()