《QT从基础到进阶·三》信号槽关联类型Connection,DirectConnection,QueuedConnection,BlockingQueuedConnection

简介: 《QT从基础到进阶·三》信号槽关联类型Connection,DirectConnection,QueuedConnection,BlockingQueuedConnection

1、常用的信号槽关联类型

(1)Qt:: Connection

自动连接:默认的方式。信号发出的线程和糟的对象在一个线程的时候相当于:DirectConnection, 如果是在不同线程,则相当于QueuedConnection。

当信号发出后,对应的槽函数将马上被调用。emit语句后的代码将在全部槽函数运行完成后被运行。在这个线程内是顺序运行、同步的。可是与其他线程之间肯定是异步的了。

(2)Qt::DirectConnection(直连方式)(信号与槽函数关系类似于函数调用。同步运行)

直接连接:相当于直接调用槽函数,但是当信号发出的线程和槽的对象不再一个线程的时候,则槽函数是在发出的信号中执行的。

当信号发出后,对应的槽函数将马上被调用。emit语句后的代码将在全部槽函数运行完成后被运行。在这个线程内是顺序运行、同步的。

如果信号所在线程和槽函数所在线程不是一个线程,会强制把槽函数拉到和信号所在的一样的线程来执行,并且是同步执行,这时打印的槽函数线程和信号线程ID是一个ID,emit后面的内容需要等到槽函数执行完毕才执行。

(3)Qt::QueuedConnection(排队方式)(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信。异步运行)

当信号发出后。排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号。调用对应的槽函数。emit语句后的代码将在发出信号后马上被运行。无需等待槽函数运行完成。

(4)Qt::BlockingQueuedConnection (信号和槽必须在不同的线程中。否则就产生死锁)

阻塞连接:发出信号后,当前线程emit后的程序会阻塞,等待槽函数执行完毕后才继续执行,相当于是不同的线程能够同步起来运行。

这个特别要注意,如果线程没启动,那信号和槽依然在同一线程,会死锁,吃了好几次亏了,一定一定要启动线程!!!

(5)Qt::UniqueConnection

防止重复连接。如果当前信号和槽已经连接过了,就不再连接了。同步异步机制与默认方式一样。

容易错的案例1:

MLAlignmentWrapper类中有两个函数,SetModel和startAlignmentMV。

SetModel函数中有信号槽的连接,startAlignmentMV函数中有信号的触发,当触发该信号后会执行

MLAlignmentModel类中的startSpotFind函数功能。

startSpotFind函数中有部分代码如下:

connect(this, SIGNAL(updateSpotData(QList<SpotData>))), widget, SLOT(updateCameraSpotData(QList<SpotData>))), Qt::BlockingQueuedConnection)
connect(this, SIGNAL(updateSpotTableData(QList<SpotData>))), widget, SLOT(updateDotsSpotData(QList<SpotData>))), Qt::BlockingQueuedConnection)
emit updateSpotData(m_SpotDataList);
emit updateSpotTableData(m_SpotTableDataList);

MLAlignmentWrapper类已经被MoveToThread,假设这个线程已被启动并执行线程的startALignmentMV方法。emit信号驱动执行m_AlignmentModel的startSpotFind方法,如果MLAlignmentModel没有move到一个线程,那它就属于主线程,this和Widget同属于一个线程,那connect后有Block连接会死锁,如果move到了一个线程,那emit startMVSignal后m_AlignmentModel就开启了一个线程,内部有Block连接可以走通。如果把startALignmentMV函数中的emit注释,把上面的注释打开,现在startALignmentMV是一个线程的方法在执行m_AlignmentModel->startSpotFind,不管MLAlignmentModel有没有move到一个线程,startSpotFind都属于MLAlignmentWrapper线程,因为我直接调用的是AlignmentModel方法没有启动线程,在startSpotFind内部打印线程ID是和MLAlignmentWrapper线程ID一样的,那startSpotFind中的this属于MLAlignmentWrapper线程,Widget属于主线程,不同线程自然Block连接方式可以走通。

现在做个修改:SetModel里的connect加个Block连接方式,不把MLAlignmentWrapper类move到一个线程,那么MLAlignmentWrapper就属于主线程,MLAlignmentModel类move到一个线程,在emit startMVSignal后就启动了MLAlignmentModel线程,并执行connect内容,因为this和m_AlignmentWidget属于不同的线程,想要同步执行,后面得要加Block连接,这时候主线程需要等待startSpotFind执行完才继续走,而内部connect连接的this属于MLAlignmentModel线程,alignmentWidget属于主线程,想要同步执行后面得要加Block连接,这样的话就有个问题,前面是主线程需要等MLAlignmentModel线程执行完才走,后面是MLAlignmentModel线程需要等主线程执行完才走,形成死循环。

易错的案例2:

回调函数在线程中循环被调用,connect在主线程被连接,这样的话emit属于子线程触发,在主线程执行showImage(),后面加block属于不同线程同步执行,emit之后需要等主线程showImage走完才接着走子线程的qDebug打印。如果我在主线程执行了子线程的join()功能,那么会阻塞主线程直到子线程结束,这样的话,子线程需要等主线程走完才走,而主线程被阻塞需要等子线程走完,形成死循环。



相关文章
|
7月前
Qt第二课 核心机制信号槽
Qt第二课 核心机制信号槽
76 1
|
7月前
|
XML 安全 C++
DBus类型系统以及在Qt和C++ 中的使用(二)
DBus类型系统以及在Qt和C++ 中的使用
210 0
|
7月前
|
XML 存储 Unix
DBus类型系统以及在Qt和C++ 中的使用(一)
DBus类型系统以及在Qt和C++ 中的使用
501 0
|
7月前
|
存储 API C++
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
658 0
|
2月前
|
存储 Linux C语言
(2)Qt中的字符串类型
本文介绍了Qt中的字符串类型QByteArray和QString,包括它们的构造函数、数据操作方法、查找操作、遍历操作以及与其他类型之间的转换,并解释了它们之间的区别。
174 5
(2)Qt中的字符串类型
|
7月前
【qt】核心机制信号槽(下)
【qt】核心机制信号槽(下)
47 1
|
7月前
|
消息中间件 存储 安全
深入理解 Qt 信号槽:高效沟通的桥梁
深入理解 Qt 信号槽:高效沟通的桥梁
832 1
|
4月前
QT信号槽
QT信号槽
44 0
|
6月前
|
编译器
(16):深入 Qt5 信号槽新语法
(16):深入 Qt5 信号槽新语法
|
6月前
Qt 信号槽(笔记)
Qt 信号槽(笔记)