Qt的signal和slot是同步的,还是异步的?

本文深入探讨了Qt中signal和slot机制的同步与异步特性,揭示了它们的行为取决于连接类型及发送者与接收者所在线程的关系。

我们知道Qt以他的signal和slot机制独步天下。但大家在用的时候有没有注意过,signal和slot是异步的,还是同步的呢?为此我问过不少Qt的使用者,有人说是同步的,有人说是异步的,也有人说着要看Qt的当时心情了¥%&*

其实是异步还是同步,是用户决定的。如果大家仔细看过connect函数的介绍就知道,connect最后的有一个参数 Qt::ConnectionType type 他将决定是异步还是同步(具体的类型可以参见帮助)。只不过平常我们使用的时候,他默认成了Qt::AutoConnection。有的兄台看到这里的时候,就会问,啥是Auto模式。其实Auto模式,就是看Qt的心情来决定是异步还是同步。而决定这个心情的就是,sender和receiver的他们分别所处的线程。如果是同一线程则就是同步调用,如果不在同一线程就是异步调用。

但真相果真如此吗?正像青春永驻的柯南君所指出的,真相永远都隐藏在表面之下。

请各位看官思考以下案例:

class A : public QObject

{

friend class B;

Q_OBJECT


public:

A ()

{

connect(this,SIGNAL(signalTest()),this,SLOT(slotTest()), Qt::AutoConnection);

}


  ............

signals:

void signalTest();

public slots:

void slotTest();


}


如果这时候我在另外一个线程触发signalTest(), 这时候signalTest和slotTest是同步还是异步呢? 根据帮助的说明,在Auto模式下,如果sender和receiver在同一线程里,

应该是同步调用。

但真相却是,他们是异步调用的。

参见Qt代码,

  // determine if this connection should be sent immediately or
            // put into the event queue
            if ((c->connectionType == Qt::AutoConnection
                 && (currentThreadData != sender->d_func()->threadData
                     || receiver->d_func()->threadData != sender->d_func()->threadData))
                || (c->connectionType == Qt::QueuedConnection)) {
                queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
                continue;
            } else if (c->connectionType == Qt::BlockingQueuedConnection) {
                blocking_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
                continue;
            }

从代码我们可以看出,在Auto模式下,如果当前线程不和sender是同一个线程,即使receiver和sender在同一线程,也将是异步调用。

太凶残了



Qt 的信号与槽机制既可以是同步的,也可以是异步的,具体行为取决于连接类型对象所在的线程环境。 当信号槽在同一个线程中被调用时,默认情况下信号槽是同步执行的。也就是说,当一个信号被发射时,连接的槽函数会立即在同一线程中执行,发射信号的代码会阻塞,直到槽函数执行完毕。这种行为被称为直接连接(`Qt::DirectConnection`)[^1]。 反之,当信号槽位于不同的线程中时,默认情况下使用的是队列连接(`Qt::QueuedConnection`)。此时,信号的发射不会立即触发槽函数的执行,而是将该事件放入事件队列中,等待接收对象所在的线程的事件循环处理。这种机制实现了异步执行的效果,发射信号的线程不会被阻塞[^1]。 此外,Qt 还提供了其他连接类型,如 `Qt::AutoConnection`(默认值,根据线程自动选择连接方式)、`Qt::BlockingQueuedConnection`(跨线程阻塞式队列连接,发射信号的线程会被阻塞直到槽执行完毕)等,开发者可以根据具体需求选择合适的连接方式。 ### 示例代码 以下是一个展示信号同步异步行为的简单示例: ```cpp #include <QObject> #include <QDebug> #include <QThread> #include <QTimer> class Sender : public QObject { Q_OBJECT public: void emitSignal() { emit mySignal(); } signals: void mySignal(); }; class Receiver : public QObject { Q_OBJECT public slots: void mySlot() { qDebug() << "Slot executed in thread:" << QThread::currentThreadId(); } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Sender sender; Receiver receiver1, receiver2; // 同步连接(同一对象,同一线程) QObject::connect(&sender, &Sender::mySignal, &receiver1, &Receiver::mySlot); // 异步连接(跨线程) QThread thread; receiver2.moveToThread(&thread); QObject::connect(&sender, &Sender::mySignal, &receiver2, &Receiver::mySlot); thread.start(); qDebug() << "Emitting signal..."; sender.emitSignal(); QTimer::singleShot(1000, &app, &QCoreApplication::quit); app.exec(); thread.quit(); thread.wait(); return 0; } #include "main.moc" ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值