在Qt应用程序中,我可以使用什么来取代睡眠和睡眠?

时间:2009-12-23 01:05:20

标签: c++ multithreading qt

我将部分现有代码导入到我的Qt应用程序中,并注意到其中有一个睡眠功能。我看到这种类型的函数在事件编程中没有地位。我该怎么做呢?

更新:经过思考和反馈我会说答案是:只在GUI主线程外调用sleep,如果你需要在GUI线程中等待使用processEvents()或事件循环,这将阻止GUI冻结

5 个答案:

答案 0 :(得分:12)

它不漂亮,但我在Qt mailing list archives中找到了这个:

QThread的sleep方法受到保护,但您可以像这样公开它:

class SleeperThread : public QThread
{
public:
    static void msleep(unsigned long msecs)
    {
        QThread::msleep(msecs);
    }
};

然后打电话:

SleeperThread::msleep(1000);

来自任何主题。

然而,更优雅的解决方案是重构代码以使用QTimer - 这可能需要您保存状态,以便在计时器关闭时知道该怎么做。

答案 1 :(得分:9)

我不建议在基于事件的系统中睡觉但是如果你想... 您可以使用等待条件,这样如果需要,您可以随时中断 sleep

//...
QMutex dummy;
dummy.lock();
QWaitCondition waitCondition;
waitCondition.wait(&dummy, waitTime);
//...

答案 2 :(得分:6)

睡眠在基于事件的编程中是一个坏主意的原因是因为基于事件的编程实际上是非抢占式多任务处理的一种形式。通过调用sleep,可以防止任何其他事件变为活动状态,从而阻止线程的处理。

在udp数据包的请求响应方案中,发送请求并立即等待响应。 Qt具有良好的套接字API,可确保套接字在等待事件时不会阻塞。事件将在它到来时发生。在你的情况下,QSocket :: readReady信号是你的朋友。

如果您希望在将来的某个时间点安排活动,请使用QTimer。这将确保不阻止其他事件。

答案 3 :(得分:3)

根本没有必要打破这些事件。我需要做的就是调用QApplication::processEvents() sleep()所在的位置,这可以防止GUI冻结。

答案 4 :(得分:2)

我不知道QT如何在内部处理事件,但在最低级别的大多数系统上,应用程序的生命周期如下:主线程代码基本上是一个循环(消息循环 ),在每次迭代中,应用程序调用一个给它一个新消息的函数;通常该函数是阻塞的,即如果没有消息,则函数不返回并且应用程序停止。

每次函数返回时,应用程序都有一个要处理的新消息,通常有一些收件人(发送到的窗口),含义(消息代码,例如鼠标指针已移动)和一些附加消息数据(例如,鼠标已经移动到coords 24,12 )。

现在,应用程序必须处理消息;操作系统或GUI工具包通常在引擎盖下执行此操作,因此使用一些黑魔法将消息分派给其收件人并执行正确的事件处理程序。当事件处理程序返回时,调用事件处理程序的内部函数返回,调用它的那个函数返回,依此类推,直到控件返回到主循环,现在将再次调用魔术消息检索函数来获取另一条消息。此循环一直持续到应用程序终止。

现在,我写了这一切,让你理解为什么在事件驱动的GUI应用程序中睡眠不好:如果你注意到,在处理消息时没有其他消息可以处理,因为主要线程忙于运行事件处理程序,毕竟,它只是消息循环调用的函数。因此,如果您让事件处理程序休眠,消息循环也会休眠,这意味着同时应用程序将不会接收和处理任何其他消息,包括使窗口重新绘制的消息,因此您的应用程序将看起来“从用户的角度来看。

长话短说:除非你必须睡很短的时间(最多几百毫秒),否则不要使用睡眠,否则GUI将无法响应。您有几个选项可以替换 sleep :您可以使用计时器(QTimer),但可能需要您在计时器事件和其他事件之间进行大量记账。一种流行的替代方案是启动一个单独的工作线程:它只处理UDP通信,并且与主线程分开,在必要时不会导致任何问题。显然,你必须注意保护线程之间使用互斥锁共享的数据,并注意避免竞争条件和多线程发生的所有其他类型的问题。