我正在使用C ++ / Qt中的线程,每个线程都要建立并保留QTcpSocket连接。
问题是当网络断开连接时,这些线程必须按特定顺序重新连接。这已经有了,但我还有另外一个问题:如果只有当前线程断开连接,或者所有线程都已断开,我需要知道每个线程。
我的第一个想法是将每个线程传递给一个类,在那里我可以存储每个线程状态并检查其他人的。
但后来我有一个更简单的想法,我想知道它是否有用或是否不可能:使用Qt的插槽和信号。
因此,我所拥有的每个线程都来自同一个类,但将不同的数据传递给Ctor。因此,我们的想法是在该类中创建一个槽和一个信号,连接它们并发出传递ID的信号。然后,每个线程的插槽都将被启动......或者我可能完全错误,启动的唯一插槽将是发出信号的同一个线程中的插槽。
这可能与否?
答案 0 :(得分:3)
首先,信号槽连接在QObjects中的信号和槽之间完成,而不是在线程之间。好吧,QThread是一个QObject,但你真的不应该从QThread派生出来。不要从QThread派生,你会没事的。
你做的是:
获取一个或多个QThreads 启动(不仅仅是构建)。那些QThreads只是基本的Qt类,不是从它们派生出来的。已启动的原始QThread被阻止,等待事件发布到其事件队列。 QThread::run()
的默认实现调用QEventLoop::exec()
(或等效的)。因此,这些线程在启动后不会占用任何CPU周期。
实例化一堆QObject。根据需要进行所有信号/插槽连接。
通过调用{{1>}对象将这些对象移动到一个或多个QThreads。
如您所见,设置信号插槽连接是以通常的方式完成的,不需要特别注意。 Qt为您完成所有工作,包括在线程之间移动QObject时将连接类型从moveToThread(QThread*)
更改为Qt::DirectConnection
。
请注意,您不能直接在这些QObject上调用任何方法,因为您可能会从不同的线程中这样做,因此会因为访问未被序列化而发生各种不好的事情。您必须执行以下任何操作,并且只能按照从最快到最慢的顺序执行。请注意,虽然#3总是比#4快,但您需要在#2和#3之间进行基准测试,因为它会发生变化。
将自定义事件发布到QObject,并在派生的QObject的Qt::QueuedConnection
方法中处理它。
使用信号槽连接,并发出连接到QObjects插槽的信号。
在先前查找的方法上使用customEvent(QEvent*)
。比#4快,因为方法查找只提前一次完成。
使用QMetaMethod::invoke
。
向QObjects发布QEvent比使用信号槽调用更快,因为没有调用复制构造函数,除了在构造QEvent时直接由你完成编组。
只有在分析/基准测试显示事件发布太慢时,您才会想要使用QMetaObject::invokeMethod
。拥有过多的QThread会产生相反的效果,您可能不应该超过系统上的CPU核心数。使用诸如互斥锁或信号量之类的同步原语需要您提交太多线程。你肯定不想要每个连接有一个线程! Qt已经为每个QObject提供了一个事件队列互斥锁,方法是使用你已经使用过的事件队列。
答案 1 :(得分:2)
信号和插槽连接在运行时完成,即您正在连接类的特定实例。您无法发出信号并将其“广播”到您班级的每个实例。不同线程之间的信号是可能的,但维护它们可能有点麻烦(在the documentation中已经很好地解释了这一点。)
如果我是你,我可能会调查QSemaphore或QSharedMemory。