目录
4. Qt::BlockingQueuedConnection
一、信号和槽简介
在Qt中,信号和槽是一种松散耦合的通信机制,允许对象之间通过事件驱动的方式进行通信。当一个对象的状态发生变化,它会发出一个信号,其他对象可以连接该信号的槽来响应这个事件。
每个QObject派生类都有一个对应的元对象(QMetaObject),元对象中包含了该类的相关信息,包括信号和槽函数的签名以及它们在对象中的偏移量。元对象表是一个静态数据结构,它存储了所有QObject派生类的元对象。
当建立连接时,Qt会将连接关系存储在发送者对象的元对象中。这样,在发送信号时,元对象系统可以遍历发送者对象的元对象表,找到所有连接到该信号的槽函数。
具体的查找过程如下:
-
获取发送者对象的元对象指针。
-
在元对象中找到与信号名称匹配的信号索引。信号索引是通过元对象的信号列表中的顺序确定的。
-
对于该信号,获取连接的槽函数数量。
-
遍历每个连接的槽函数:
- 获取槽函数的签名。
- 在元对象中找到与槽函数签名匹配的槽函数索引。
- 通过槽函数索引,获取槽函数的指针或偏移量。
- 将槽函数指针或偏移量与信号的参数一起传递给元对象系统,以便调用槽函数。
需要注意的是,由于在编译时生成的MOC代码中包含了元对象的信息,所以元对象系统能够在运行时进行信号和槽的匹配和调用。
总结起来,元对象系统通过遍历发送者对象的元对象表,并根据信号和槽函数的签名进行匹配,找到连接的槽函数。这个过程涉及元对象表的查找、信号索引的匹配以及槽函数的获取。通过这种方式,元对象系统能够在运行时实现信号和槽的连接和调用。
二、五种信号和槽的连接方式
在Qt中,共有五种不同的信号和槽连接方式:
1. Qt::AutoConnection
Qt::AutoConnection是默认连接类型。如果信号接收方与发送方在同一个线程,它将使用Qt::DirectConnection,否则使用Qt::QueuedConnection。连接类型在信号发射时决定。
MyObject obj1, obj2;
// 自动连接信号和槽
QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot);
2. Qt::DirectConnection
Qt::DirectConnection将导致信号所连接的槽函数立即在发射信号的线程中执行。这意味着槽函数的执行与信号的发射是同步的。如果槽函数执行耗时操作或信号由UI线程发射,可能会导致UI无响应。
MyObject obj1, obj2;
// 直接连接信号和槽
QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot, Qt::DirectConnection);
3. Qt::QueuedConnection
Qt::QueuedConnection将导致槽函数在接收者所在的线程中执行。这种连接方式下,如果信号被多次触发,相应的槽函数会按照顺序在接收者线程中依次执行。注意:使用QueuedConnection时,参数类型必须是Qt基本类型,或者使用qRegisterMetaType()进行注册的自定义类型。
MyObject obj1, obj2;
// 队列连接信号和槽
QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot, Qt::QueuedConnection);
4. Qt::BlockingQueuedConnection
Qt::BlockingQueuedConnection与Qt::QueuedConnection类似,区别在于发送信号的线程在槽函数执行完毕之前会一直处于阻塞状态。因此,发送方和接收方必须处于不同的线程,否则可能导致死锁。
MyObject obj1, obj2;
// 创建新线程
QThread* workerThread = new QThread;
obj1.moveToThread(workerThread);
workerThread->start();
// 阻塞队列连接信号和槽
QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot, Qt::BlockingQueuedConnection);
5. Qt::UniqueConnection
Qt::UniqueConnection可以与以上所有连接类型搭配使用。一旦设置了Qt::UniqueConnection,同一信号与同一槽函数的二次连接将会失败,确保了连接的唯一性。
MyObject obj1, obj2;
// 连接信号和槽,并指定UniqueConnection
QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot, Qt::UniqueConnection);
三、总结
在使用信号和槽时,我们需要根据具体的场景来选择合适的连接方式。在单线程应用程序中,直接连接通常是最常用的方式。而在多线程应用程序中,为了避免竞争条件和数据不一致问题,建议使用队列连接或使用信号和槽结合QThread或QtConcurrent来实现异步通信。
Qt中五种不同的信号和槽连接方式在多线程环境下的应用非常重要。根据不同的需求和场景,选择合适的连接方式能够保证程序的高效运行和数据的安全处理。