Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python QThread没有完成_Python_Python 3.x_Pyqt_Pyqt5 - Fatal编程技术网

Python QThread没有完成

Python QThread没有完成,python,python-3.x,pyqt,pyqt5,Python,Python 3.x,Pyqt,Pyqt5,我正在构建一个GUI,其中套接字连接在PyQt5中的反向线程中运行。除了Qthread从未发出完成的信号外,其他一切都运行得很好。也许这不是问题,我可以改变我的实现来解决它,但是一旦移动的对象停止执行任何操作,Qthread将继续运行的预期行为是什么呢 我应该在主类中编写一个函数,在完成后停止线程,还是可以将新的内容移动到该线程而不产生任何后果 class MyClass(PyQt5.QtWidgets.QMainWindow) def __init__(self, parent=Non

我正在构建一个GUI,其中套接字连接在PyQt5中的反向线程中运行。除了Qthread从未发出完成的信号外,其他一切都运行得很好。也许这不是问题,我可以改变我的实现来解决它,但是一旦移动的对象停止执行任何操作,Qthread将继续运行的预期行为是什么呢

我应该在主类中编写一个函数,在完成后停止线程,还是可以将新的内容移动到该线程而不产生任何后果

class MyClass(PyQt5.QtWidgets.QMainWindow)
    def __init__(self, parent=None):

        # Setup thread for the socket control
        self.simulThread = PyQt5.QtCore.QThread()
        self.socketController = SocketController()
        self.socketController.moveToThread(self.simulThread)
        self.simulThread.started.connect(self.socketController.controlSocket)

        self.simulThread.finished.connect(self.deadThread)

        # Bind controls to events
        self.ui.buttonConnect.clicked.connect(self.simulThread.start)
        self.ui.buttonDisconnect.clicked.connect(lambda: self.socketController.stop())

   def deadThread(self, data):
       print ("THREAD IS DEAD.")

class SocketController(PyQt5.QtCore.QObject):
    finished       = PyQt5.QtCore.pyqtSignal()

    def __init__(self):
        super(SocketController, self).__init__()
        self.run = True;

    def controlSocket(self):
        #setup the socket

        while self.run:
            # do socket stuff
            time.sleep(1)

        #close the socket
        self.finished.emit()

    def stop(self):
        self.run = False;
QThread有自己的事件循环来处理信号。controlSocket方法阻止此事件循环,直到self.run==False。但这永远不会发生,因为self.run仅在控件返回到事件lop时设置为False,并且它可以处理运行stop方法的信号

您可能希望重新构造线程,这样就不用使用while循环来阻止QThread事件循环,而是在线程中构造一个QTimer,每1秒调用一次do套接字代码。这样,控制返回到线程事件循环,它可以处理停止信号,该信号将被更改为停止QTimer再次触发。

QThread有自己的事件循环来处理信号。controlSocket方法阻止此事件循环,直到self.run==False。但这永远不会发生,因为self.run仅在控件返回到事件lop时设置为False,并且它可以处理运行stop方法的信号


您可能希望重新构造线程,这样就不用使用while循环来阻止QThread事件循环,而是在线程中构造一个QTimer,每1秒调用一次do套接字代码。这样,控制返回到threads事件循环,它可以处理停止信号,该信号将被更改为停止QTimer再次触发,因此我找到了一个解决方案,但我不知道它是否正确。我没有将disconnect按钮映射到socket stop函数,而是将其映射到MyClass中定义的函数,该函数调用我编写的名为controlDisconnect的新函数,该函数还显式地告诉线程退出

# The changed line
self.ui.buttonDisconnect.clicked.connect(self.controlDisconnect)

def controlDisconnect(self):
    self.socketController.stop()
    self.simulThread.quit()

虽然这是工作线程打印出的消息,表明它死了,我不确定这是真正的好做法。可能至少应该有一些代码来确保socketController在告诉线程退出之前已经实际停止

好的,我找到了一个解决方案,但我真的不知道它是否正确。我没有将disconnect按钮映射到socket stop函数,而是将其映射到MyClass中定义的函数,该函数调用我编写的名为controlDisconnect的新函数,该函数还显式地告诉线程退出

# The changed line
self.ui.buttonDisconnect.clicked.connect(self.controlDisconnect)

def controlDisconnect(self):
    self.socketController.stop()
    self.simulThread.quit()

虽然这是工作线程打印出的消息,表明它死了,我不确定这是真正的好做法。可能至少应该有一些代码来确保socketController在告诉线程退出之前已经实际停止

答案实际上是三个菠萝和OP在他们的答案中的组合:

正如three_Pinepples所指出的,主要问题是controlSocket在发出started信号时由线程事件循环调用,直到调用stop方法后才会返回。然而,在OP的设计中,如果套接字线程可以处理事件,那么stop方法只能由Qt调用,因为这是通过事件循环调度跨线程信号的方式。当controlSocket忙于循环和睡眠时,这是不可能的。 为了使线程退出,必须停止其事件循环。 第一个问题必须通过允许线程在循环期间处理事件,或者使用计时器而不是循环来解决。处理事件显示在这段代码中,基于操作代码:

import time

from PyQt5.QtWidgets import QMainWindow, QWidget, QPushButton, QApplication, QHBoxLayout
from PyQt5.QtCore import QThread, QObject, pyqtSignal

class MyClass(QWidget):
    def __init__(self, parent=None):
        super().__init__()

        self.resize(250, 150)
        self.setWindowTitle('Simple')

        # Setup thread for the socket control
        self.socketController = SocketController()

        self.simulThread = QThread()
        self.socketController.moveToThread(self.simulThread)
        self.simulThread.started.connect(self.socketController.controlSocket)
        self.simulThread.finished.connect(self.deadThread)

        # Bind controls to events
        self.buttonConnect = QPushButton('connect')
        self.buttonConnect.clicked.connect(self.simulThread.start)

        self.buttonDisconnect = QPushButton('disconnect')
        self.buttonDisconnect.clicked.connect(self.socketController.stop)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.buttonConnect)
        hbox.addWidget(self.buttonDisconnect)
        self.setLayout(hbox)

    def deadThread(self, data):
        print("THREAD IS DEAD.")


class SocketController(QObject):
    finished = pyqtSignal()

    def __init__(self):
        print('initialized')
        super().__init__()
        self.run = True

    def controlSocket(self):
        # setup the socket

        print('control socket starting')
        while self.run:
            # do socket stuff
            app.processEvents()
            print('control socket iterating')
            time.sleep(1)

        # close the socket
        self.finished.emit()
        print('control socket done')

    def stop(self):
        print('stop pending')
        self.run = False


app = QApplication([])
mw = MyClass()
mw.move(300, 300)
mw.show()
app.exec()
QTimer稍微复杂一点,但想法是让controlSocket只执行循环的一次迭代,并通过QTimer重复调用它:

QTimer.singleShot(0, self.controlSocket)

上述任一方法都修复了第一个问题,并允许SocketController停止执行与套接字相关的工作

第二个问题是,即使套接字控制器完成了它的工作,线程循环仍然在运行,这两个循环是独立的。要使事件循环退出,必须通过线程的quit方法停止它。退出和停止应同时进行:

class MyClass(QWidget):
    def __init__(self, parent=None):
        ...

        self.buttonDisconnect = QPushButton('disconnect')
        self.buttonDisconnect.clicked.connect(self.stop)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.buttonConnect)
        hbox.addWidget(self.buttonDisconnect)
        self.setLayout(hbox)

    def stop(self):
        self.simulThread.quit()
        self.socketController.stop()

答案实际上是三个菠萝和OP在他们的答案中的组合:

正如three_Pinepples所指出的,主要问题是controlSocket在发出started信号时由线程事件循环调用,直到调用stop方法后才会返回。然而,在OP的设计中,如果套接字线程可以处理事件,那么stop方法只能由Qt调用,因为这是通过事件循环调度跨线程信号的方式。当controlSocket忙于循环和睡眠时,这是不可能的。 伊诺 为了使线程退出,必须停止其事件循环。 第一个问题必须通过允许线程在循环期间处理事件,或者使用计时器而不是循环来解决。处理事件显示在这段代码中,基于操作代码:

import time

from PyQt5.QtWidgets import QMainWindow, QWidget, QPushButton, QApplication, QHBoxLayout
from PyQt5.QtCore import QThread, QObject, pyqtSignal

class MyClass(QWidget):
    def __init__(self, parent=None):
        super().__init__()

        self.resize(250, 150)
        self.setWindowTitle('Simple')

        # Setup thread for the socket control
        self.socketController = SocketController()

        self.simulThread = QThread()
        self.socketController.moveToThread(self.simulThread)
        self.simulThread.started.connect(self.socketController.controlSocket)
        self.simulThread.finished.connect(self.deadThread)

        # Bind controls to events
        self.buttonConnect = QPushButton('connect')
        self.buttonConnect.clicked.connect(self.simulThread.start)

        self.buttonDisconnect = QPushButton('disconnect')
        self.buttonDisconnect.clicked.connect(self.socketController.stop)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.buttonConnect)
        hbox.addWidget(self.buttonDisconnect)
        self.setLayout(hbox)

    def deadThread(self, data):
        print("THREAD IS DEAD.")


class SocketController(QObject):
    finished = pyqtSignal()

    def __init__(self):
        print('initialized')
        super().__init__()
        self.run = True

    def controlSocket(self):
        # setup the socket

        print('control socket starting')
        while self.run:
            # do socket stuff
            app.processEvents()
            print('control socket iterating')
            time.sleep(1)

        # close the socket
        self.finished.emit()
        print('control socket done')

    def stop(self):
        print('stop pending')
        self.run = False


app = QApplication([])
mw = MyClass()
mw.move(300, 300)
mw.show()
app.exec()
QTimer稍微复杂一点,但想法是让controlSocket只执行循环的一次迭代,并通过QTimer重复调用它:

QTimer.singleShot(0, self.controlSocket)

上述任一方法都修复了第一个问题,并允许SocketController停止执行与套接字相关的工作

第二个问题是,即使套接字控制器完成了它的工作,线程循环仍然在运行,这两个循环是独立的。要使事件循环退出,必须通过线程的quit方法停止它。退出和停止应同时进行:

class MyClass(QWidget):
    def __init__(self, parent=None):
        ...

        self.buttonDisconnect = QPushButton('disconnect')
        self.buttonDisconnect.clicked.connect(self.stop)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.buttonConnect)
        hbox.addWidget(self.buttonDisconnect)
        self.setLayout(hbox)

    def stop(self):
        self.simulThread.quit()
        self.socketController.stop()

你说的有道理,但是这行代码:self.ui.buttonDisconnect.clicked.connectlambda:self.socketController.stop似乎实际上破坏了我的while循环线程打印出for循环和套接字断开连接后的消息。所以我相信函数正在返回,但线程没有完成。我为SocketController类创建的完成信号也被断言,但不是来自simulThread的完成信号。@Ian哦,stop方法实际上正在主线程中运行,因为您将连接包装在一个lambda中,因此,Qt魔法(它可以确定运行某个线程)并不起作用,因为lambda总是存在于创建它们的线程中。所以我想我没有答案…你说的有道理,但这行代码:self.ui.buttonDisconnect.clicked.connectlambda:self.socketController.stop似乎实际上破坏了我的while循环线程打印出for循环和套接字断开连接后的消息。所以我相信函数正在返回,但线程没有完成。我为SocketController类创建的完成信号也被断言,但不是来自simulThread的完成信号。@Ian哦,stop方法实际上正在主线程中运行,因为您将连接包装在一个lambda中,因此,Qt魔法(它可以确定运行某个线程)并不起作用,因为lambda总是存在于创建它们的线程中。所以我想我没有答案…你是说线死了会被打印吗?@scholli它不会被打印。你是说线死了会被打印吗?@scholli它不会被打印。这里有些奇怪。是否调用了controlSocket方法?因为它有一个无限循环,只有在调用stop时才会停止,所以我希望这个方法在stop之前不会返回,但是stop只能由controlDisconnect调用,只有在线程处理事件时才能调用,如果它卡在一个无限循环中,这是不可能发生的……注意:在你的答案或问题中不需要lambda,但是你必须去掉调用括号。@Scholli,谢谢你对lambda的捕获,这是我的一个产物,我还没有完全理解整个线程设置。无论如何,是的,它将controlSocket绑定到线程启动事件。也许我上面发布的内容不清楚,但是controlDisconnect在主窗口中,而不是thread类。也许我误解了什么,但是controlDisconnect是MyClass的一部分,由button press事件调用。所以它的执行是独立于线程的。这里有些奇怪。是否调用了controlSocket方法?因为它有一个无限循环,只有在调用stop时才会停止,所以我希望这个方法在stop之前不会返回,但是stop只能由controlDisconnect调用,只有在线程处理事件时才能调用,如果它卡在一个无限循环中,这是不可能发生的……注意:在你的答案或问题中不需要lambda,但是你必须去掉调用括号。@Scholli,谢谢你对lambda的捕获,这是我的一个产物,我还没有完全理解整个线程设置。无论如何,是的,它将controlSocket绑定到线程启动事件。也许我上面发布的内容不清楚,但是controlDisconnect在主窗口中,而不是thread类。也许我误解了什么,但是controlDisconnect是MyClass的一部分,由button press事件调用。所以它的执行是独立于线程的。