【问题标题】:Stopping code execution for milliseconds at each iteration of loop在循环的每次迭代中停止代码执行毫秒
【发布时间】:2019-09-03 13:48:36
【问题描述】:

我在循环中调用一个函数:

for (Item *item : *items) {
    item->func();
}

被调用函数发出信号并等待100毫秒:

void Item::func()
{
    // Emit a signal
    emit castSignal();

    QTimer::singleShot(100 /* msec */, [](){
        qDebug() << "Wait for 100 milliseconds";
    });
}

我有一个插槽,当接收到信号时会记录到控制台:

QObject::connect(this, &Item::castSignal, this, &Item::handleSignal);

void Item::handleSignal()
{
    qDebug() << "Signal received";
}

我希望日志是这样的:

Signal received
Wait for 100 milliseconds
Signal received
Wait for 100 milliseconds
Signal received
Wait for 100 milliseconds

但实际的日志是这样的:

Signal received
Signal received
Signal received
Wait for 100 milliseconds
Wait for 100 milliseconds
Wait for 100 milliseconds

我不知道为什么!谁能帮忙。

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    singleShot 添加一个计时器,然后继续执行。当时间间隔过去时,您的 lambda 将被调用。因此,您启动了三个计时器,并且在第一个计时器的超时时间过去之前收到了所有三个信号。

    如果您确实需要func 等待 100 毫秒,请使用睡眠功能。

    【讨论】:

      【解决方案2】:

      让我们一步一步分析你的代码:

      for (Item *item : *items) {
          item->func();
      }
      

      相当于:

      emit castSignal();
      QTimer::singleShot(100 /* msec */, [](){
          qDebug() << "Wait for 100 milliseconds";
      });
      emit castSignal();
      QTimer::singleShot(100 /* msec */, [](){
          qDebug() << "Wait for 100 milliseconds";
      });
      emit castSignal();
      QTimer::singleShot(100 /* msec */, [](){
          qDebug() << "Wait for 100 milliseconds";
      });
      // ...
      

      必须考虑以下几点:

      • 在您的情况下,接收方和发送方开始同一个线程,因此由于默认使用 Qt::AutoConnection,因此会立即调用插槽。

      • 定时器在同步部分结束时和指定时间启动

      考虑到上述情况并看到 handleSignal 消耗的时间非常少,您的代码相当于:

      qDebug() << "Signal received";
      qDebug() << "Signal received";
      qDebug() << "Signal received";
      
      T: 100 ms
      
      qDebug() << "Wait for 100 milliseconds";
      qDebug() << "Wait for 100 milliseconds";
      qDebug() << "Wait for 100 milliseconds";
      

      得到你得到的行为。

      @1201ProgramAlarm 表示相同,但​​使用 sleep 是一个不好的选择,因为它会阻塞事件循环,阻止其他信号、事件等正常运行,而可能的选择是使用 QEventLoop:

      void Item::func()
      {
          // Emit a signal
          emit castSignal();
          QEventLoop loop;
      
          QTimer::singleShot(100 /* msec */, [&loop](){
              qDebug() << "Wait for 100 milliseconds";
              loop.quit();
          });
          loop.exec();
      }
      

      【讨论】:

      • QEventLoop 解决了我的问题。感谢您的帮助 =)
      最近更新 更多