0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Qt中的三个exec之间有什么联系

嵌入式小生 来源:嵌入式小生 2023-03-06 09:44 次阅读

一、导读

在Qt中,常见到三个exec,第一个是QApplication::exec(),第二个是QEventLoop::exec,第三个是QThread::exec()。本文从源码角度来看看这三个exec()。

QApplication::exec()是QApplication类下的一个静态成员函数,该函数用于进入主事件循环。

QEventLoop::exec是QEventLoop类下的一个公共成员函数,用于进入主事件循环。

QThread::exec()是QThread类下的一个受保护的成员函数,也是用于进入事件循环。

都是进入事件循环,他们之间有什么联系呢,接着后面的分析。

二、QApplication::exec()

在实际开发中,必须调用QApplication::exec()来启动事件处理,主事件循环会从窗口系统接收事件,并将这些事件分派给应用程序小部件。在调用exec()之前不能发生任何用户交互,但是存在一种特殊的情况:QMessageBox这样的模态小部件可以在调用exec()之前使用,因为模态小部件会调用exec()来启动本地事件循环。

从源码角度,QApplication::exec()会调用QGuiApplication::exec(),QGuiApplication::exec()会调用QCoreApplication::exec():

intQCoreApplication::exec()
{
//检查exec实例
if(!QCoreApplicationPrivate::checkInstance("exec"))
return-1;

//获取线程数据QThreadData
QThreadData*threadData=self->d_func()->threadData;

//检查该函数的调用是否在主线程中,如果不是,则返回。
if(threadData!=QThreadData::current()){
qWarning("%s:Mustbecalledfromthemainthread",self->metaObject()->className());
return-1;
}
//检查是否存在事件循环,如果存在,则返回,否则继续后续操作。
if(!threadData->eventLoops.isEmpty()){
qWarning("QCoreApplication:Theeventloopisalreadyrunning");
return-1;
}

threadData->quitNow=false;
//创建QEventLoop事件循环对象
QEventLoopeventLoop;
self->d_func()->in_exec=true;
self->d_func()->aboutToQuitEmitted=false;
//启动事件循环
intreturnCode=eventLoop.exec();
threadData->quitNow=false;

if(self)
self->d_func()->execCleanup();

returnreturnCode;
}

从上述源码可见,QApplication的exec()经过层层调用,最终是使用QEventLoop实现事件循环。

QApplication::exec()用于启动应用程序的事件循环,让应用程序能得以启动运行并接收事件。

『备注,执行应用清理的优雅方式』:

建议将清理代码连接到aboutToQuit()信号,而不是放在应用程序的main()函数中。这是因为,在某些平台上,QApplication::exec()调用可能不会返回。例如,在Windows平台上,当用户注销时,系统会在Qt关闭所有顶级窗口后终止该进程。因此,不能保证应用程序有足够的时间退出事件循环,并在QApplication::exec()调用之后,即在main()函数的末尾执行代码。

在QCoreApplication::exec()函数实现中的这几行代码:

if(threadData!=QThreadData::current()){
qWarning("%s:Mustbecalledfromthemainthread",self->metaObject()->className());
return-1;
}

引发出另一个有趣的知识点,那就是:在Qt多线程开发中,需要注意不要阻塞GUI线程,那么哪个是GUI线程呢?从上述源码可以明确知道:QApplication a(argc, argv);所在线程就是GUI线程。

三、QThread::exec()

在多线程应用设计中,QThread::exec()用于为当前线程启动一个新的事件循环,为存在于该线程中的对象交付事件。在源码中,QThread::exec()实现如下:

intQThread::exec()
{
Q_D(QThread);
QMutexLockerlocker(&d->mutex);
d->data->quitNow=false;
if(d->exited){
d->exited=false;
returnd->returnCode;
}
locker.unlock();
//创建QEventLoop事件循环。
QEventLoopeventLoop;
intreturnCode=eventLoop.exec();

locker.relock();
d->exited=false;
d->returnCode=-1;
returnreturnCode;
}

从源码角度,也可见QThread::exec()实现中也调用到QEventLoop的exec()。

四、QEventLoop::exec()

QEventLoop::exec()用于进入主事件循环并等待直到exit()被调用。在调用该函数时需要传入一个flags,如果指定了标志,则只处理标志允许的类型的事件,Qt中支持以下几种标志:

序号 标志类型 描述
1 QEventLoop::AllEvents 所有事件
2 QEventLoop::ExcludeUserInputEvents 不处理用户输入事件,例如ButtonPress和KeyPress。
3 QEventLoop::ExcludeSocketNotifiers 不要处理套接字通知事件。
4 QEventLoop::WaitForMoreEvents 如果没有可用的挂起事件,则等待事件。

注意,没有被传递的事件不会被丢弃,这些事件将在下次传入不过滤事件的标志调用procesvents()时被传递。

从源码角度,QEventLoop::exec()实现如下:

intQEventLoop::exec(ProcessEventsFlagsflags)
{
Q_D(QEventLoop);
autothreadData=d->threadData.loadRelaxed();

//weneedtoprotectfromraceconditionwithQThread::exit
QMutexLockerlocker(&static_cast(QObjectPrivate::get(threadData->thread.loadAcquire()))->mutex);
if(threadData->quitNow)
return-1;

if(d->inExec){
qWarning("QEventLoop:instance%phasalreadycalledexec()",this);
return-1;
}

structLoopReference{
QEventLoopPrivate*d;
QMutexLocker&locker;

boolexceptionCaught;
LoopReference(QEventLoopPrivate*d,QMutexLocker&locker):d(d),locker(locker),exceptionCaught(true)
{
d->inExec=true;
d->exit.storeRelease(false);

autothreadData=d->threadData.loadRelaxed();
++threadData->loopLevel;
threadData->eventLoops.push(d->q_func());

locker.unlock();
}

~LoopReference()
{
if(exceptionCaught){
qWarning("Qthascaughtanexceptionthrownfromaneventhandler.Throwing
"
"exceptionsfromaneventhandlerisnotsupportedinQt.
"
"YoumustnotletanyexceptionwhatsoeverpropagatethroughQtcode.
"
"Ifthatisnotpossible,inQt5youmustatleastreimplement
"
"QCoreApplication::notify()andcatchallexceptionsthere.
");
}
locker.relock();
autothreadData=d->threadData.loadRelaxed();
QEventLoop*eventLoop=threadData->eventLoops.pop();
Q_ASSERT_X(eventLoop==d->q_func(),"QEventLoop::exec()","internalerror");
Q_UNUSED(eventLoop);//--releasewarning
d->inExec=false;
--threadData->loopLevel;
}
};
LoopReferenceref(d,locker);

//当进入一个新的事件循环时,删除已发布的exit事件
QCoreApplication*app=QCoreApplication::instance();
if(app&&app->thread()==thread())
QCoreApplication::removePostedEvents(app,QEvent::Quit);

#ifdefQ_OS_WASM
//Partialsupportfornestedeventloops:MaketheruntimethrowaJavaSrcript
//exception,whichreturnscontroltothebrowserwhilepreservingtheC++stack.
//Eventprocessingthencontinuesasnormal.Thesleepcallbelowneverreturns.
//QTBUG-70185
if(threadData->loopLevel>1)
emscripten_sleep(1);
#endif

while(!d->exit.loadAcquire())
processEvents(flags|WaitForMoreEvents|EventLoopExec);

ref.exceptionCaught=false;
returnd->returnCode.loadRelaxed();
}

从上述源码可知,QEventLoop::exec()本质会调用 processEvents()分发事件。 processEvents()实现如下:

cc77bc0a-bb5e-11ed-bfe3-dac502259ad0.png

从上图所示代码中,会调用QAbstractEventDispatcher::processEvents()实现事件分发。QAbstractEventDispatcher类提供了一个管理Qt事件队列的接口,它从窗口系统和其他地方接收事件。然后它将这些事件发送到QCoreApplication或QApplication实例进行处理和交付。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 程序
    +关注

    关注

    116

    文章

    3754

    浏览量

    80724
  • 源码
    +关注

    关注

    8

    文章

    632

    浏览量

    29100
  • 多线程
    +关注

    关注

    0

    文章

    277

    浏览量

    19891
  • 函数
    +关注

    关注

    3

    文章

    4276

    浏览量

    62303
  • Qt
    Qt
    +关注

    关注

    1

    文章

    301

    浏览量

    37774

原文标题:Qt这三个exec,傻傻分不清!

文章出处:【微信号:嵌入式小生,微信公众号:嵌入式小生】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    proteussounder speaker buzzer 三个什么不同

    proteussounder speaker buzzer 三个什么不同,之前就发现了,但是一直很模糊,求助啊。。。。
    发表于 05-20 18:18

    labview如何实现三个事件互锁?

    labview如何实现三个事件互锁?即三个布尔量只允许一输出为TRUE,剩下两FALSE。有人能指点小弟一二吗
    发表于 10-26 14:25

    Qt学习常用的类

    学的原因所在)。其实在QT你会发现有QApplication和return *.exec()是必须有的这也是QT运行时的机制, 当执行到 *.ex
    发表于 10-18 09:47

    如何用C语言编写图上的三个方波的编程,能否解读下三个方波之间联系

    如何用C语言编写图上的三个方波的编程,能否解读下三个方波之间联系,老师给的方波,表示没看懂,不知如何从何下手
    发表于 12-05 16:02

    请问这之间什么联系

    工程师朋友,你好:我是新手,想问升压型DC-DC芯片的开关电流Isw、输出电流Iout和芯片的耗电,之间什么联系
    发表于 07-04 08:33

    如何鉴别可控硅的三个

    如何鉴别可控硅的三个极 鉴别可控硅三个极的方法很简单,根据P-N结的原理,只要用万用表测量一下三个之间的电阻值就可以。
    发表于 12-02 08:34 887次阅读

    鉴别可控硅三个极的方法

    鉴别可控硅三个极的方法 鉴别可控硅三个极的方法很简单,根据P-N结的原理,只要用万用表测量一下三个之间的电
    发表于 01-14 16:20 1221次阅读

    实施智能制造需要考虑三个支点

    笔者在《论智能制造》系列的“论智能制造的三个阶段”,谈到了对三个阶段的基本认识。而如何实施智能制造,则需要考虑智能制造的三个支点:产品、
    发表于 11-06 15:31 896次阅读

    闲聊HDMI、DVI、VGA三个接口的区别及联系

    今天来聊聊一篇关于dvi接口:HDMI、DVI、VGA接口什么联系的文章,现在就为大家来简单介绍下dvi接口:HDMI、DVI、VGA接口什么联系,希望对各位小伙伴们有所帮助。
    发表于 07-17 10:55 5382次阅读

    谈谈PCBA、SMT、PCB之间区别与联系

    很多刚开始接触电子行业的人,常常会被PCBA、SMT、PCB这三个给弄混,很难分清楚它们之间的区别和联系,接下来众焱电子就通过通俗易懂的语言来谈谈PCBA、SMT、PCB
    的头像 发表于 03-19 09:31 3w次阅读

    Qt Designer、Qt Quick Designer和Qt Creator应用程序什么区别?

    Designer与之类似,只是用于构建QML GUI,而两者都内置在Qt Creator。 我们通过使用它们的方法来解释这些工具之间的区
    的头像 发表于 03-17 09:40 7153次阅读

    mosfet的三个电极怎么区分 mos管三个极电压关系

    MOSFET(金属氧化物半导体场效应晶体管)三个主要电极,分别是栅极(Gate)、漏极(Source)和源极(Drain)。这三个电极的区分方法如下
    的头像 发表于 09-18 12:42 3.2w次阅读

    docker exec命令的使用方法

    Docker是一种开源的容器化平台,可以让开发人员在容器打包和运行应用程序。它提供了一种快速、可靠和一致的方式来构建、部署和运行应用程序。Docker exec命令是Docker提供的一非常
    的头像 发表于 11-23 09:33 1515次阅读

    晶体管的三个极的电压关系大小

    晶体管是一种半导体器件,用于放大电信号、开关电路和逻辑运算等。它是现代电子技术和计算机科学的核心之一。在晶体管三个电极:基极、发射极和集电极。这三个电极的电压
    的头像 发表于 12-20 14:50 5660次阅读

    微波测量的三个基本参量是什么

    微波测量是电子工程领域中的一重要分支,它涉及到对微波信号的频率、幅度、相位等参数的测量。在微波测量三个基本参量:频率、幅度和相位。这三个
    的头像 发表于 05-28 14:46 989次阅读