QMutex 是否需要保护信号?

Do signals need to be protected by a QMutex?

我正在使用 PyQt5 和 2 个 QThreads 开发一个 GUI,它们将使用各自的信号加上一个用于将错误代码发送回 GUI 的共享信号。我知道 QThreads 是要与 pyqtSignals 一起使用的,但是除了你从两个不同的线程发出共享信号之外,它们的行为是否与信号有关? 此外,在共享信号上使用 Qmutex 是否会确保线程同时访问它,或者在处理信号时它是否无用?

我写了这个示例代码,它运行正常,但我不确定信号是如何处理的:

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


class Class2(QThread):
    def __init__(self, signal):
        super().__init__()
        self.signal2 = signal

    def run(self):
        self.signal2.emit("Class 2 signal emitted")


class Class1(QThread):
    def __init__(self, signal):
        super().__init__()
        self.signal1 = signal

    def run(self):
        self.signal1.emit("Class 1 signal emitted")


class Action(QObject):
    shared_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        class1 = Class1(self.shared_signal)
        class2 = Class2(self.shared_signal)
        self.shared_signal.connect(self.action)
        class1.start()
        class2.start()
        time.sleep(1)

    def action(self, buffer):
        print(buffer)


app = QCoreApplication([])
Action = Action()
sys.exit(app.exec_())

感谢您的帮助!

信号本身是线程安全的,因为它们的主要任务是对信息进行排队,为此使用了互斥体。


                ┌----------------------┐
                |                      |
                |         QUEUE        |
                |                      |
                └----------------------┘
                  ▲ ▲ ... ▲   | |     |
                  | |     |   ▼ ▼ ... ▼
                   SIGNALS      SLOTS

连接可能不是线程安全的,因为它取决于连接的类型。我建议您阅读 the docs 以了解哪种连接是不安全的(例如,在不同线程上的 QObject 之间使用 Qt::DirectConnection)。


在你的情况下,连接是安全的,另一方面,我认为 time.sleep 没有必要,但这会导致对象在调用信号之前被销毁,因此可能的解决方案是:

import sys


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


class Class2(QThread):
    def __init__(self, signal, parent=None):
        super().__init__(parent)
        self.signal2 = signal

    def run(self):
        self.signal2.emit("Class 2 signal emitted")


class Class1(QThread):
    def __init__(self, signal, parent=None):
        super().__init__(parent)
        self.signal1 = signal

    def run(self):
        self.signal1.emit("Class 1 signal emitted")


class Action(QObject):
    shared_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        class1 = Class1(self.shared_signal, self)
        class1.finished.connect(class1.deleteLater)

        class2 = Class2(self.shared_signal, self)
        class2.finished.connect(class2.deleteLater)

        self.shared_signal.connect(self.action)
        class1.start()
        class2.start()

    @pyqtSlot(str)
    def action(self, buffer):
        print(buffer)


def main():

    app = QCoreApplication([])
    action = Action()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()