【问题标题】:QMutexLocker() causes UI to freezeQMutexLocker() 导致 UI 冻结
【发布时间】:2012-08-02 09:25:49
【问题描述】:

我有一个控制机器人的控制器类(通过串行接口连接)。此控制器附加到视图。除此之外,我还有一个源自QThread 的线程,它会定期读出机器人的状态。

读取状态不得与从用户界面触发的机器人命令发生冲突。因此,我使用QMutexLocker 用互斥锁锁定了每个机器人的访问权限,但是如果执行了这样的互斥锁块,这会导致我的用户界面冻结。

class RobotControl(QObject):
    def __init__(self, view):
        super(RobotControl, self).__init__()
        self.view = view
        self.updatethread = UpdatePositionAndStatus(self.robot)
        self.mutex = QMutex()
        self.connect(self.updatethread, SIGNAL("updateStatus( QString ) "), self.print_error)
        self.updatethread.start()

@pyqtSlot()  
def init_robot(self):
    """
    Initializes the serial interface to the robot interface and checks if
    there is really a robot interface available.
    """
    with QMutexLocker(self.mutex):
        # Open interface
        try:
            index = self.view.robotcontrolui.get_selected_interface_index()
            interface = self.interfaces.item(index).text()
            self.robot = RobotController(interface)
        except DeviceError:
            self.view.error_dlg(self.tr("Couldn't open interface {0}!".format(interface)))
            self.robot = None
            return

        # Check if there is really a robot interface on the selected serial
        # interface with trying to read status byte
        try:
            self.robot.status()
        except DeviceError:
            # In case of failure release interface
            self.close_robot()
            self.view.error_dlg(self.tr("Couldn't initialize robot interface!"))
            return

        self.view.robotcontrolui.bt_open_interface.setEnabled(False)
        self.view.robotcontrolui.bt_close_interface.setEnabled(True)

class UpdatePositionAndStatus(QThread):
    def __init__(self, robot, parent=None):
        QThread.__init__(self, parent) 
        self.robot = robot
        self.mutex = QMutex()
    def run(self):
        """ 
        This function continously reads out the position and the status to for 
        updating it on the userinterface.
        """
        try:
            while True:
                if self.robot is not None:
                    # Do robot communication under a lock
                    self.mutex.lock()
                    (_, rel_pos) = self.robot.read_position()
                    status = self.robot.status()
                    self.mutex.unlock()

                    # Display position and status on userinterface
                    self.view.robotcontrolui.update_position_and_status(rel_pos, status)

                # Wait 1 seccond for next update
                QThread.sleep(1.0)
        except DeviceError:
            # Release lock on robot
            self.mutex.unlock()
            self.emit(SIGNAL("updateStatus( QString )"), self.tr("Error while updating current position and status!"))

在触发 init 方法后,用户界面冻结,程序崩溃:为什么会这样?我怎样才能避免这种情况?

【问题讨论】:

    标签: python multithreading pyqt mutex robot


    【解决方案1】:

    很难说,因为您的代码示例不完整,但我发现此代码存在两个基本问题:

    1. 您正在锁定两个不同的 QMutex 对象。为了使互斥正常工作,两个线程必须锁定相同的互斥对象。

    2. 您似乎在这一行的更新线程中直接与 GUI 交互:

      self.view.robotcontrolui.update_position_and_status(rel_pos, status)
      

      执行 GUI 操作只能在 Qt 的 GUI 线程中完成。可以肯定的是,这会导致您的崩溃。见:http://qt-project.org/doc/qt-4.8/threads.html

    【讨论】:

    • @1:感谢您的提示。现在改为一个互斥体,但也没有解决问题。 @2:RobotControl 保存在主 QApplication 中,因此它位于 GUI 线程内。在异常中显示错误对话框也可以调用 gui。我知道这个问题 - 这就是更新线程不直接调用 gui 而不是发送插槽的原因。明天我正在尝试制作一个最小的示例。
    • RobotControl 是从主线程中定义的并不重要;对 update_position_and_status 的调用来自 UpdatePositionAndStatus.run,它在单独的线程中运行。唯一可以接受的方法是 update_position_and_status 不直接与 GUI 交互,而是安全地将消息传递给 GUI 线程,告诉它如何更新。
    • 不是直接调用该方法,而是发出另一个信号,表明您的主线程已连接并调用该方法。卢克的好答案。
    • 哦,我误会你了。没错 update_position_and_status() 必须在信号内调用。不过,我通过删除附加线程来减少我的问题。现在只有 init_robot() 具有互斥锁。我设置了一个断点,并直接在with QMutexLocker() 语句之后用户界面开始冻结。
    • 听起来你因为锁定该互斥锁太多次而陷入僵局。由于您将线程取出(这很好——除非您希望长时间等待串行响应,否则它们可能是不必要的),不再需要互斥锁;把它们拿出来。
    猜你喜欢
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 2017-01-22
    相关资源
    最近更新 更多