我正在用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
线程安全的可能是连接,因为它取决于连接的类型。我推荐你阅读 文献 来知道什么样的连接是不安全的(例如使用 Qt::DirectConnection
在不同线程上的QObjects之间)。)
在你的情况下,连接是安全的,另一方面,我认为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()