问题
信号与槽是QT特有的一种功能吧,当使用connect函数将一个信号于一个槽函数绑定过后,那么信号当emit后,就会执行与之绑定的槽函数,那么问题来了,这个执行方式是怎样的,是立刻的还是异步的。如果是立刻的就是以中断形式去执行的,异步的也就是通过事件循环方式去执行的。
是以中断形式去执行的?既当信号emit后就立即去执行槽函数,槽函数结束后返回,继续执行emit语句后的语句。
还是以事件循环形式执行的?既当信号emit后,当成一个事件,进入事件队列,经由事件循环,最终去执行。
探索问题
抱着上述问题,我们首先找到connect函数,先看其函数原型(connect函数有重载,我们找个我们最常用的那个),如下:
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver,const char *method, Qt::ConnectionType type = Qt::AutoConnection)
我们主要看其中connect的参数:
const QObject *sender 发出信号的对象指针
const char *signal 信号指针
const QObject *receiver 接收信号的对象指针
const char *method 待绑定的方法,也就是槽函数
Qt::ConnectionType type = Qt::AutoConnection 连接方式
我们在习惯性用的connect函数一般只设置四个参数,对最后一个参数不进行设置,即一般是下面这种情况:
connect(myButton, SIGNAL(clicked()),
this, SIGNAL(buttonClicked()));
那么为了要了解执行方式,我们是时候了解下对后一个参数的含义了,经查手册可以看到Qt::ConnectionType可以有以下几种情况:
![连接方式](https://img-blog.csdnimg.cn/20200620111710398.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NjE0NjI4OA==,size_16,color_FFFFFF,t_70)
可以看到,一般有五种连接方式,下面结合我使用经验大致解释下:
Qt::AutoConnection:这个是连接方式自动,也就是我们的默认连接方式,它的含义是当发送信号的对象和接收信号的槽函数如果在同一个线程里面就用Qt::DirectConnection,反之就用Qt::QueuedConnection。
Qt::DirectConnection:这个是直接连接,也就是数当信号触发后立即去执行槽函数,即中断方式,只有当槽函数返回才会继续执行emit语句后的语句。注意此种连接方式的槽函数会在发送者线程里面去执行。
Qt::QueuedConnection:这种是队列连接,也就是信号会以一个事件形式进入事件队列,等待执行。注意此种连接方式的槽函数将会在接收者所在的线程中去执行。因为这种方式需要经过一个事件循环,所以可以理解成异步的方式。
Qt::BlockingQueuedConnection和Qt::UniqueConnection:有了上述的理解,这两个应该结合引文就直接可以明白了,我就不解释了,偷个懒。
得到结论
经过上面的分析我们可以知道,一般常用的connect后执行方式有两种方式:
1、中断方式
2、异步方式
中断方式只需要将连接方式换成Qt::DirectConnection就可以了。
异步方式只需要将连接方式换成Qt::QueuedConnection就可以了。
验证结论
为验证以上结论我做了简单的测试(关于在不同线程之间我没做,变得也就是槽函数在哪个线程里面执行的而已)。分两步测试验证中断方式和异步方式。
中断方式测试
测试中断方式我们采用如下代码
connect(this,SIGNAL(testsignal()),
this,SLOT(testslot()),Qt::DirectConnection);
void Widget::testslot()
{
qDebug()<<"testslot";
}
void Widget::on_pushButton_5_clicked()
{
emit testsignal();
qDebug()<<"testsignal";
}
按照上面的分析,当采用中断方式连接后,对于上述代码肯定先执行qDebug()<<"testslot"
然后在执行qDebug()<<"testsignal"
。那么运行程序可以看到以下结论:
![结论](https://img-blog.csdnimg.cn/20200620115043820.png)
结论:采用Qt::DirectConnection链接后的槽函数,将会在emit触发信号后立即去执行对应的槽函数,待槽函数返回后才会继续执行emit语句后的语句。
异步方式测试
我门将connect函数,最后一个参数改成Qt::QueuedConnection进行测试,
connect(this,SIGNAL(testsignal()),
this,SLOT(testslot()),Qt::QueuedConnection);
那么当我点击按钮时如果是异步方式上述更改后的代码应该是先执行qDebug()<<"testsignal";
然后再去执行qDebug()<<"testslot";
。那么运行程序可以看到以下结论:
![结论](https://img-blog.csdnimg.cn/20200620120108234.png)
结论:采用Qt::QueuedConnection链接后的槽函数,在emit后会以一个事件形式进入事件队列,等待事件循环时去执行,不影响emit后的语句。因此可以理解为异步的链接。