在我的 Qt 应用程序中,我可以用啥来代替 sleep 和 usleep?
Posted
技术标签:
【中文标题】在我的 Qt 应用程序中,我可以用啥来代替 sleep 和 usleep?【英文标题】:what can I use to replace sleep and usleep in my Qt app?在我的 Qt 应用程序中,我可以用什么来代替 sleep 和 usleep? 【发布时间】:2010-12-29 08:10:24 【问题描述】:我将现有代码的一部分导入到我的 Qt 应用程序中,并注意到其中有一个睡眠功能。我看到这种类型的函数在事件编程中没有位置。我应该怎么做?
更新:经过思考和反馈,我会说答案是:仅在 GUI 主线程外调用 sleep,如果您需要在 GUI 线程中等待,请使用 processEvents() 或事件循环,这将防止 GUI 冻结.
【问题讨论】:
sleep()
是做什么用的?
它用作发送UDP数据包和接收应答之间的延迟。
这个 QTime 解决方案不会在午夜失败吗?
是的。更好的解决方案是 QWaitCondition 或类似的东西。
【参考方案1】:
它不漂亮,但我在Qt mailing list archives 中找到了这个:
QThread 的 sleep 方法是受保护的,但你可以这样暴露它:
class SleeperThread : public QThread
public:
static void msleep(unsigned long msecs)
QThread::msleep(msecs);
;
然后只需调用:
SleeperThread::msleep(1000);
来自任何线程。
但是,一个更优雅的解决方案是重构您的代码以使用 QTimer - 这可能需要您保存状态,以便您知道在计时器关闭时该怎么做。
【讨论】:
是的,我知道这些方法,并且 SleeperThread 类似乎是更好的选择,但我正在评估在主线程中使用 sleep 是否是有效的做法,因为它似乎违背了事件编程的做法。跨度> 恕我直言,这不是一个好习惯 - 您应该使用使用信号和插槽的 Qt UDP 套接字类,以便您知道何时有数据要读取以及何时安全写,等等。 好点。但现在我认为这将需要我对我的代码进行极大的碎片化。例如。我调用 getUDPdata(COMMAND_BYTE) 发送数据包并收到回复。在我使用这些数据之后的代码行中。如果我按照你说的做,那么我将不得不 rdo 整个程序,事情会变得非常复杂,你不是说吗? 我认为硬编码休眠——希望之后有可供读取的数据——是一个坏主意,最终会咬你一口。如果可能,我会重构代码。【参考方案2】:我不建议在基于事件的系统中睡眠,但如果你想... 您可以使用等待条件,这样您就可以在必要时随时中断睡眠。
//...
QMutex dummy;
dummy.lock();
QWaitCondition waitCondition;
waitCondition.wait(&dummy, waitTime);
//...
【讨论】:
【参考方案3】:在基于事件的编程中睡眠是一个坏主意的原因是因为基于事件的编程实际上是非抢占式多任务处理的一种形式。通过调用 sleep,您可以防止任何其他事件变为活动状态并因此阻塞线程的处理。
在 udp 数据包的请求响应场景中,发送请求并立即等待响应。 Qt 具有良好的套接字 API,可确保套接字在等待事件时不会阻塞。事件来了就会来。在您的情况下, QSocket::readReady 信号是您的朋友。
如果您想在未来某个时间点安排活动,请使用 QTimer。这将确保不会阻止其他事件。
【讨论】:
如前所述 sleep 或 usleep 会阻塞事件循环,导致 GUI 死机。这意味着用户将无法取消操作,甚至无法彻底退出应用程序。正确的方法是使用状态机en.wikipedia.org/wiki/Finite-state_machine。欢迎来到事件驱动编程的世界。【参考方案4】:根本没有必要分解事件。我需要做的就是调用QApplication::processEvents()
所在的sleep()
,这样可以防止GUI 冻结。
【讨论】:
【参考方案5】:我不知道 QT 如何在内部处理事件,但在大多数处于最低级别的系统上,应用程序的生命周期是这样的:主线程代码基本上是一个循环(消息循环 ),其中,在每次迭代中,应用程序调用一个函数,给它一个新消息;通常该函数是阻塞的,即如果没有消息,该函数不会返回并且应用程序会停止。
每次函数返回时,应用程序都有一条新消息要处理,通常有一些接收者(发送到的窗口)、含义(消息代码,例如鼠标指针已移动)和一些附加信息数据(例如,鼠标已移动到 坐标 24、12)。
现在,应用程序必须处理消息;操作系统或 GUI 工具包通常在后台执行此操作,因此通过一些黑魔法将消息发送给其接收者并执行正确的事件处理程序。当事件处理程序返回时,调用事件处理程序的内部函数返回,调用它的内部函数也返回,依此类推,直到控制返回主循环,现在将再次调用神奇的消息检索函数来获取另一个消息。这个循环一直持续到应用程序终止。
现在,我写这一切是为了让您了解为什么在事件驱动的 GUI 应用程序中睡眠不好:如果您注意到,在处理消息时无法处理其他消息,因为主线程忙于运行您的事件处理程序,毕竟这只是消息循环调用的一个函数。所以,如果你让你的事件处理程序休眠,消息循环也会休眠,这意味着应用程序在此期间不会接收和处理任何其他消息,包括那些让你的窗口重绘的消息,所以你的应用程序看起来“从用户的角度来看。
长话短说:不要使用睡眠,除非你必须睡眠很短的时间(最多几百毫秒),否则 GUI 将变得无响应。您有几个选项来替换 sleeps:您可以使用计时器 (QTimer),但它可能需要您在计时器事件和另一个事件之间做大量的记账。一种流行的替代方法是启动一个单独的工作线程:它只处理 UDP 通信,并且与主线程分开,在必要时不会导致任何问题睡眠。显然,您必须注意使用互斥锁保护线程之间共享的数据,并小心避免竞争条件和多线程发生的所有其他类型的问题。
【讨论】:
不得不下班,但我一定会在今晚晚些时候阅读你的帖子;)以上是关于在我的 Qt 应用程序中,我可以用啥来代替 sleep 和 usleep?的主要内容,如果未能解决你的问题,请参考以下文章
BaseJQueryEventObject、JQueryEventObject 等已弃用。我们用啥来代替它?