打印

几种延时处理方法

[复制链接]
989|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
问天少年|  楼主 | 2022-6-1 10:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
[color=rgba(0, 0, 0, 0.5)]来源地址:
https://blog.csdn.net/qq_31073871/article/details/80472347
嵌入式软件开发过程中,基本都会用到“延时”,本文分享几种Qt种延时处理方法。
一、阻塞型延时

阻塞的原理就是:在延时期间,本线程的事件循环得不到执行。

1、QThread类的sleep()

最简单的延时方法就是使用QThread类的sleep(n)、msleep(n)、usleep(n),这几个函数的不良后果就是,GUI会在延时的时间段内失去响应,界面卡死,所以,这三个函数一般用在非GUI线程中。

QThread::msleep(50);//阻塞延时50ms


使用特权

评论回复
沙发
问天少年|  楼主 | 2022-6-1 10:11 | 只看该作者
2、使用定时器:死等
void Delay_MSec_Suspend(unsigned int msec)
{   
    QTime _Timer = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < _Timer );
}



使用特权

评论回复
板凳
问天少年|  楼主 | 2022-6-1 10:12 | 只看该作者
二、非阻塞延时

原理无非就是利用事件循环,有两种原理:

1、处理本线程的事件循环

在等待中,不断强制进入当前线程的事件循环,这样可以把堵塞的事件都处理掉,从而避免程序卡死

void Delay_MSec(unsigned int msec)
{
    QTime _Timer = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < _Timer )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
2、使用子事件循环

创建子事件循环,在子事件循环中,父事件循环仍然是可以执行的

void Delay_MSec(unsigned int msec)
{
    QEventLoop loop;//定义一个新的事件循环
    QTimer::singleShot(msec, &loop, SLOT(quit()));//创建单次定时器,槽函数为事件循环的退出函数
    loop.exec();//事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
}


使用特权

评论回复
地板
问天少年|  楼主 | 2022-6-1 10:12 | 只看该作者
三、耗时代码的处理

假设有这样的应用情景:点击某个button之后,需要读入并处理一幅图像,需要耗时20秒才能处理完。

在这20s内,GUI会失去效应,界面上的任何元素都无法被点击,这种情况应该怎么办?方法有两种:1、用另一个线程去处理这个耗时任务;2、在耗时任务中,不断地去处理本线程的事件循环,以保证GUI的及时响应。

for(i=0; i < 1000000; i++)
{
    //QCoreApplication::processEvents(QEventLoop::AllEvents);    //去处理本线程的事件循环,避免本线程被堵塞
    QCoreApplication::processEvents(QEventLoop::AllEvents, 5);//如果不够频繁,可以增加第二参数来缓解卡顿

    for(j=0; j < 1000000; j++)
    {
        //QCoreApplication::processEvents(QEventLoop::AllEvents);//处理事件循环,不建议放在这里,可能过于频繁
        doSomeThing();
    }
}

一般来说,processEvents()不宜被调用的过于频繁,也不宜被调用的不够频繁。过于频繁的话,一方面会使线程的响应更好,但另一方面会导致原本就耗时的任务变得更加耗时;不够频繁的话,显然可能会使GUI线程的响应变差,例如每500ms才被调用一次,那么GUI的事件循环就只能500ms才被处理一次,当然,这个问题可以通过设定processEvents()的第二个形参略微得到缓解,更好的做法是,保证被调的周期<200ms(再小一些更好,看程序需求),这样不至于肉眼可见的卡顿。

副作用:(特别注意!)

1、在点击按钮之后,这个20s的耗时任务开始执行,尚未执行完毕时,我们点击了GUI的关闭按钮,那么GUI会立即消失,但是这个耗时任务仍然会在后台执行,直到执行完毕,进程才会退出。解决办法:重写关闭事件,在关闭事件的函数中直接结束进程。

2、在点击按钮之后,这个20s的耗时任务开始执行,执行到第5秒时,我们再次点击了这个按钮,那么QT又会执行一个新的20s任务,这个新任务完成后,又会接着把第一个20s任务从上次被打断的第5秒继续执行。如果这个任务是可重入的,后果仅仅是被执行了两遍,如果任务不可重入,那情况就彻底糟糕了。解决办法:点击按钮后把这个按钮disable掉,执行完再enable



使用特权

评论回复
5
carpsnow| | 2022-6-1 21:01 | 只看该作者
耗时代码,和空指令

再者就是定时器

使用特权

评论回复
6
caigang13| | 2022-6-2 08:10 | 只看该作者
了解了,谢谢讲解。

使用特权

评论回复
7
tpgf| | 2022-7-1 10:27 | 只看该作者
延时方式还这么多种啊

使用特权

评论回复
8
qcliu| | 2022-7-1 10:37 | 只看该作者
哪种是最常用的呢

使用特权

评论回复
9
gwsan| | 2022-7-1 11:01 | 只看该作者
处理方式还是不一样的

使用特权

评论回复
10
tfqi| | 2022-7-1 11:09 | 只看该作者
为什么会有时候卡在延时里边出不来呢

使用特权

评论回复
11
nawu| | 2022-7-1 11:16 | 只看该作者
本质上还是那些

使用特权

评论回复
12
zljiu| | 2022-7-1 11:43 | 只看该作者
每种的应用场景不同

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

73

主题

532

帖子

1

粉丝