qt事件循环阻塞机制分析

关于事件循环

  • 所有对象的exec()方法都是开启事件循环,QApplicaion::exec()为主事件循环。程序在exec()里面无限循环,能让跟在exec()后面的代码得不到运行机会,直至程序从exec()跳出
  • 事件循环能接收事件并处理。待处理事件被放在事件循环队列里顺序处理 
  • 事件循环的本质就是以队列的方式分配线程时间片,程序所有的代码都活动在事件循环里
  • 事件循环是嵌套的,子层的事件循环执行时,父事件循环中断,Qt会把事件送到当前生效的那个事件循环中

关于定时器

  • qt常用事件有鼠标事件、键盘事件、绘制事件 等,定时器事件也是qt事件的一种
  • 定时器由事件触发信号,槽函数作为执行体等同于普通函数,如果槽函数阻塞,会阻塞整个槽函数所在线程

关于模态对话框

  • 模态对话框靠exec()启动事件循环,接手父事件循环的一切责任,直到模态对话框退出
  • 模态对话框会阻塞当前事件循环后的代码段,换句话说模态对话框在父事件执行时开启新的事件循环,并且阻塞这一次父事件,但是不影响其它事件的执行。例如如果在处理按键A的相应事件代码片段中间开启一个模态对话框,这次按键A的事件将会被阻塞,但是再按其它键或者点击鼠标是可以正常处理事件的,因为此时模块对话框已经接手了事件循环。

综合分析

事件的阻塞exec()和 代码级别的阻塞(比如人为 while(1){} 或者sleep)是不一样的。表面上看都会阻塞后面的代码,但是exec()只阻塞当前事件,while(1){}是阻塞的整个线程代码。

测试代码如下:

#ifndef MYOBJECT_H_
#define MYOBJECT_H_

#include 
#include  
 
class MyObject : public QObject
{
    Q_OBJECT
public:
    MyObject();
    ~MyObject(){};
public slots:
    void update1(); 
    void update2();
    void update3();
};
 
#endif // MYOBJECT_H_
#include "myobject.h"
#include 
#include  

int i = 0;

MyObject::MyObject()
{
    QTimer *timer1 = new QTimer(this);
    connect(timer1, SIGNAL(timeout()), this, SLOT(update1()));
    timer1->start(1000);

    QTimer *timer2 = new QTimer(this);
    connect(timer2, SIGNAL(timeout()), this, SLOT(update2()));
    timer2->start(1000);

    QTimer *timer3 = new QTimer(this);
    connect(timer3, SIGNAL(timeout()), this, SLOT(update3()));
    timer3->start(1000);
}

void MyObject::update1()
{
    qDebug() << "update1:" << i;
    i++;
    QDialog myDialog;
    myDialog.exec();
}

void MyObject::update2()
{
    qDebug() << "update2:" << i;
    i++;
    while (1)
    {
    }
    //QDialog myDialog;
    //myDialog.show();
}

void MyObject::update3()
{
    qDebug() << "update3:" << i;
    i++;
    //QDialog myDialog;
    //myDialog.show();
}
#include 
#include "myobject.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyObject myObject;
    return a.exec();
}

本例单线程环境,创建了3个定时器,相当于3个事件来源,上述代码定时器2中槽函数中死循环阻塞整个线程,所有事件都无法相应。执行结果如下(线程卡住不动了,定时器没有继续触发):

qt事件循环阻塞机制分析_第1张图片

 

代码改成如下后,定时器1中产生模态对话框,阻塞当前事件的处理,但是不影响定时器2和3的逻辑处理,此时定时器2中的非模态对话框和定时3都可以轮训执行。

#include "myobject.h"
#include 
#include  

int i = 0;

MyObject::MyObject()
{
    QTimer *timer1 = new QTimer(this);
    connect(timer1, SIGNAL(timeout()), this, SLOT(update1()));
    timer1->start(1000);

    QTimer *timer2 = new QTimer(this);
    connect(timer2, SIGNAL(timeout()), this, SLOT(update2()));
    timer2->start(1000);

    QTimer *timer3 = new QTimer(this);
    connect(timer3, SIGNAL(timeout()), this, SLOT(update3()));
    timer3->start(1000);
}

void MyObject::update1()
{
    qDebug() << "update1:" << i;
    i++;
    QDialog myDialog;
    myDialog.exec();
}

void MyObject::update2()
{
    qDebug() << "update2:" << i;
    i++;
    QDialog myDialog;
    myDialog.show();
}

void MyObject::update3()
{
    qDebug() << "update3:" << i;
    i++;
}

执行结果如下:

qt事件循环阻塞机制分析_第2张图片

模态对话框阻塞的只是当前事件,不是当前代码段,这一点明白了才是真的明白了

比如改成如下:

qt事件循环阻塞机制分析_第3张图片

效果上是弹出3个模块对话框,但是3个事件都被阻塞。

你可能感兴趣的:(qt,c++)