qt延时之界面“假死”问题

转载自:https://blog.csdn.net/xiezhongyuan07/article/details/81169583

在Qt程序中,我们有时候会遇到这样的需求,比如让程序暂停(休息、休眠)一段时间, 这段时间里可能程序什么都不做, 也可能是在后台开了个子线程在做一些用户看不见的工作。

最开始我需要这样的需求时候,我第一反应想到的是在QT Assistant 中搜索sleep方法,企图寻找让程序暂停、休眠一段时间的方法,不过,搜索结果显然令我很失望,并没有找到直接满足需求的sleep方法,不过看到了QThread中的sleep的方法:

[static] void QThread::sleep(unsigned long secs);//Forces the current thread to sleep for secs seconds.

这个好像和我们的需求类似,就试一下吧。

QThread::sleep(5000);

好吧,结果却是下面这样,也就是程序直接崩溃了。

究其原因:

  • 原来界面的线程是主线程,在主线程中使用休眠函数是一种错误,这会直接导致界面无法刷新,用户与程序无法交互,最终导致程序崩溃。linux提供的”sleep”或”usleep”函数会将你当前的线程/进程变为“睡眠”状态。 这个“睡眠”是深度意义的睡眠, 睡眠期间内核不会分配给程序时间片, 所以程序什么都不做, 更不用提界面的刷新了。 直接导致的问题就是用户无法与程序交互。 所以说直接使用sleep函数睡眠是常见的错误方案之一。
  • 多线程程序使用sleep()、msleep()、usleep()、wait()进行延时处理。Sleep不会释放对象锁,其他线程无法访问对象,因此会阻塞线程;而Wait会释放对象锁,使得其他线程能够访问该对象。

我们要记住最重要的一点:我们永远不需要让主线程休眠,但是,我们有时候会需要让程序等一段时间。

那么如何让程序等待一段时间呢? 对,有的小伙伴可能已经想到了使用定时器或者死循环等方式,如下:


QTime time;

time.start();

while(time.elapsed() < 5000); //等待时间流逝5秒钟

这样做会存在一个问题,当在死循环的时候,我们的界面是无法刷新,用户是不会响应用户的任何交互的。也就是让用户感觉程序已经是假死状态了。 从代码中我们可以发现在while循环中不停的调用elapsed()函数, 等于在这段时间内CPU完全没有机会做别的什么事情。 特别是在Linux这样非抢占式的操作系统中, 这样的死循环造成的影响是致命的, CPU被完全占用, 内核都没有机会调度进程, 别的程序拿不到时间片执行, 系统基本上就是瘫痪状态了。 无论如何, 这种结果都不是我们想要的。(当然拉, 除非你想写的是病毒程序。) 对于我们的程序本身, 虽然它占用了所有的CPU, 但由于它陷入该循环, 程序没有机会进入到GUI事件循环, 导致同样界面是无法刷新的。

那么怎样改成正确的呢? 只需要在死循环的时候,不停地处理事件,让程序保持响应。


QTime time;

time.start();

while(time.elapsed() < 5000)             //等待时间流逝5秒钟
{
    QCoreApplication::processEvents();   //处理事件
    //usleep(10000);//sleep和usleep都已经obsolete,建议使用nanosleep代替
}

    

为解决CPU占用率过高的问题,可以让程序适当的睡眠。这里设置程序睡眠一段很短很短的时间, 对于用户来说是不会有什么感觉的, 但对内核来说就意义大不同。 这样内核就有充足的时间调度进程/线程, 让其他程序有机会执行。

其实还有另外一种方式实现类似的效果,就是定时器与QEventLoop配合使用:


    QEventLoop eventloop;

    QTimer::singleShot(5000, &eventloop, SLOT(quit()));

    eventloop.exec();

猜你喜欢

转载自blog.csdn.net/qq_35820102/article/details/85524623