首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QEventLoop在QTimer槽中的应用

QEventLoop在QTimer槽中的应用
EN

Stack Overflow用户
提问于 2022-03-21 14:17:31
回答 1查看 172关注 0票数 0

我在同一个线程中有多个QTimer,在连接到QTimer的插槽中,我使用QEventLoop进行同步,就像http请求一样,但是我发现当它们以不同的顺序启动时,不同的QTimers可能会相互影响。

下面是我的简单测试代码片段:

案例1

代码语言:javascript
复制
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTimer t1;
    QTimer t2;
    QObject::connect(&t1, &QTimer::timeout, []()->void{
                         qDebug() << QDateTime::currentDateTimeUtc() << "T1...";
                         QEventLoop loop;
                         // t1 slot run time 3000ms
                         QTimer::singleShot(3000, &loop, SLOT(quit()));
                         loop.exec();
                     });
    QObject::connect(&t2, &QTimer::timeout, []()->void{
                         qDebug() << QDateTime::currentDateTimeUtc() << "T2...";
                         QEventLoop loop;
                         // t2 slot run time 100ms
                         QTimer::singleShot(100, &loop, SLOT(quit()));
                         loop.exec();
                     });
    // interval 1000ms, start t1 first and then t2
    t1.start(1000);
    t2.start(1000);
    return a.exec();
}

输出:

代码语言:javascript
复制
QDateTime(2022-03-21 14:00:51.014 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:00:51.016 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:00:54.025 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:00:54.027 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:00:58.018 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:00:58.019 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:01:01.014 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:01:01.015 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:01:04.016 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:01:04.016 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:01:07.019 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:01:07.020 UTC Qt::TimeSpec(UTC)) T1...

从输出中可以看到,t2受t1影响,实际间隔约为3000~4000 is,对于t1和t2,我认为t2不应该受到影响。

案例2

只需更改QTimer启动顺序,但事情会变得不同

代码语言:javascript
复制
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTimer t1;
    QTimer t2;
    QObject::connect(&t1, &QTimer::timeout, []()->void{
                         qDebug() << QDateTime::currentDateTimeUtc() << "T1...";
                         QEventLoop loop;
                         // t1 slot run time 3000ms
                         QTimer::singleShot(3000, &loop, SLOT(quit()));
                         loop.exec();
                     });
    QObject::connect(&t2, &QTimer::timeout, []()->void{
                         qDebug() << QDateTime::currentDateTimeUtc() << "T2...";
                         QEventLoop loop;
                         // t2 slot run time 100ms
                         QTimer::singleShot(100, &loop, SLOT(quit()));
                         loop.exec();
                     });
    // interval 1000ms, start t2 first and then t1
    t2.start(1000);
    t1.start(1000);
    return a.exec();
}

输出:

代码语言:javascript
复制
QDateTime(2022-03-21 14:04:53.653 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:04:53.656 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:54.659 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:55.655 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:56.656 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:04:56.656 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:57.664 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:58.657 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:59.665 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:04:59.667 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:00.660 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:01.662 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:02.652 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:03.650 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:05:03.653 UTC Qt::TimeSpec(UTC)) T2...

现在t1不再影响t2,t1的实际间隔约为3000~4000 is,t2约为1000 is。

我真的很困惑,为什么不同的开始顺序会有不同的结果。有人能帮我解释一下吗?

平台:QT5.5.0 MinGW 32位,Windows

IDE: Qt Creator 3.4.2

您可以直接在main()中运行我的测试代码并检查测试结果。

谢谢。

编辑1:

我使用QEventLoop来同步RESTFul API的http请求,如下所示:

代码语言:javascript
复制
// m_http is QNetworkAccessManager
QNetworkReply *reply = m_http->get(request);
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();

在计时器插槽中,只有一个同步http请求来轮询数据。通常情况下,请求会很快完成,但如果出现错误,有时会花费超过1000 it。我的应用程序需要同时与多个服务器通信,每个连接都有一个计时器来执行轮询,所有连接实例都在同一个线程中,因此所有计时器共享相同的事件循环。我的测试是模拟请求的一种简单方法,使用QTimer::singleShot作为按请求计算的时间开销。在QT中是否有更好的方法来同步http请求?使用QEventLoop可能不是最好的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-21 15:37:47

首先,检查您的QTimer::timerType():默认的是Qt::CoarseTimer,它有5%的精度。您可能需要Qt::PreciseTimer代替。

其次,主Qt事件循环将序列化所有事件。不管他们是什么。它是一个独特的管道(它很容易成为应用程序的瓶颈,BTW)。在处理某些事件(如鼠标事件)之前,它也有“打包”某些事件的坏习惯。

最后,一个QTimer::singleShot也是一个真正的定时器,您可以在一个插槽内启动一个--这基本上是在事件循环上下文中执行的,您在两个不同的 QEventLoop对象上手动调用事件循环处理.

老实说,你的计时器做奇怪的事情并不奇怪。你能准确地说出你需要用这些定时器做什么吗?因为您的QEventLoop技巧所做的唯一一件事是在请求期间阻塞/搅乱计时器,即T1为3000 ms,T2为100 ms,这显然会与您为每个请求的基本1000 ms周期相混淆.

通常,您将接收信号(finished(QNetworkReply*)表示QNetworkAccessManager,但将是readyRead()表示QIODevice)连接到您的插槽,并且使用sender()允许单个时隙同时处理各种对象。您不需要手动同步任何东西,而是让Qt为您处理--这是使用框架的好处之一。因此,“回覆接收”就是这样做的。

对于发送请求,这取决于你。您可以使用各种解决方案:

一旦请求,

  1. 立即发送它们(即通过一个按钮将它们发送到FIFO容器中,使用QTimer发送它们,而不会同时敲碎机器和服务器。请求被推入缓冲区ASAP.
  2. Threading (这部分是要小心的)--使用Qt,您将需要大部分时间调用moveToThread()才能使它正常工作。

我更喜欢解决方案2,为每个目标服务器提供一个队列和一个特定的定时器--这将允许一个非常基本的QoS,并将避免对一个服务器的大量请求禁止使用其他服务器。在此之前,您可以使用dispatcher函数,该函数将通过映射自动选择要使用的正确队列,该映射关联服务器名称(如果需要的话是+协议)及其特定的队列和定时器。

当您什么都不做,请求(它们都被发送)并且等待回复时,您让主Qt事件循环完成它的工作:避免阻塞消息泵--它将产生“应用程序没有响应”消息。此外,它还允许减少CPU负载,获取应用程序的所有鼠标事件,并像进度条一样刷新GUI元素。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71559111

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档