QT消息/事件循环机制与多线程的关系

关于Qt子线程和消息循环
一、QT消息/事件循环机制

Qt作为一个可视化GUI界面操作系统,是基于事件驱动的,我们程序执行的顺序不再是线性,而是由一个个应用程序内部或外部的事件进行驱动,无事件时便阻塞。这个循环概念类似于while的函数循环,函数体内不断处理用户的输入,类比到事件循环中,用户点击了鼠标、按下了键盘,便被称作为事件。
一般对于带UI窗口的程序来说,“事件”是由操作系统或程序框架在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,计时器触发的时候,都会发出一个相应的事件。我们把“事件循环”的代码 提炼/抽象 如下
function eventloop() {
    initialize();
    bool shouldQuit = false;
    while(false == shouldQuit)
    {
        var message = get_next_message();
        process_message(message);
        if (message == QUIT) 
        {
            shouldQuit = true;
        }
    }
}
 


机制解释
这样的程序运行流程,我们叫做“事件驱动”式的程序。一般的Qt程序,main函数中都有一个QCoreApplication/QGuiApplication/QApplication,并在末尾调用 exec。Application中的这个EventLoop,我们称作“主事件循环”,所有的事件分发、事件处理都从这里开始。Application还提供了sendEvent和poseEvent两个函数,分别用来发送事件。sendEvent发出的事件会立即被处理,也就是“同步”执行。postEvent发送的事件会被加入事件队列,在下一轮事件循环时才处理,也就是“异步”执行。
函数阻塞
我们常常使用Qt来编写UI界面,这样确实很方便,但是Qt的事件循环机制在这里会出现一些问题。举两个例子:

 

比如说:假设我们有一个鼠标点击事件,事件循环会分发出这个鼠标点击事件,调用特定的鼠标事件处理函数,但是这个信号却做了很多耗时的事情,于是便堵塞着、等待着事件处理函数返回,这是堵塞了时间循环,它意味着没有消息被分发了,再次有事件或消息时无法被及时分发处理,直到我们从槽函数返回了,然后才能继续处理挂起的消息。
再比如说:我们有时候又需要做一些复杂的计算,这段计算程序就在我们的UI界面的事件循环中,这些计算的耗时甚至达到了几秒钟,在没有计算完成之前,函数不会退出(相当于阻塞),事件循环得不到及时处理,就会发生UI卡住的现象。
多线程使用
以上两种情况,在消息循环被卡住的情况下,widgets将不能更新它们自身,不可能有更多的互动,timers将不会被激发,网络通讯将缓慢下来,或者停止。进一步的说,许多窗口管理器将检测到你的应用程序不在处理事件了, 然后告诉用户你的程序没有响应。这就是为什么快速的对事件响应并且即时返回到事件循环是多么的重要。

对于上述两种情况,假如我们有一个很长的任务去运行但是又不希望堵塞这个消息循环,该怎么做呢?可行的方法如下:
将这个任务移到另一个线程中,
我们也能手动强制事件循环去运行,这个方法是通过在堵塞的任务函数中调用QCoreApplication::processEvent()来实现,QCoreApplication::processEvent()将处理所有在消息队列中的消息并返回给调用者。
另一个可选的选项是我们能够强制重入事件循环的对象,就是QEventLoop类。通过调用QEventLoop::exec()我们将重入事件循环,然后我们能将槽函数QVentLoop::quit()连接到信号上去使它退出。
其中最常用的是创建子线程的办法
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值