关于c ++:QTimer :: timeout不触发

QTimer::timeout isn't firing

我正在尝试创建一个事件,该事件在我的Singleton worker中每n秒触发一次。 信号/插槽连接(信号为QTimer超时,插槽为lambda函数,该函数调用另一个Singleton类)不起作用。 连接呼叫成功,计时器处于活动状态,并且控制台上没有QTimer投诉。 如果我尝试打印QTimer的剩余时间,它将显示为-1。 对于我的一生,我无法弄清楚为什么从未打印"超时"(表明事件已被触发)。 任何帮助将不胜感激。 为了简单起见,我们可以假设OtherSingleton具有相同的结构。 我还应注意,此Singleton类对象在QThread内部运行。

Singleton.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <QObject>
#include <string>
#include <QTimer>
#include <QThread>

class Singleton : public QObject
{
   Q_OBJECT

public:
    static Singleton& get_instance();

    Singleton(Singleton const&) = delete;
    void operator=(Singleton const&) = delete;

    static void stop_client();

    static void start_client();

private:
    Singleton();

    static QTimer bytes_timer_;

};

Singleton.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include"Singleton.h"
#include <QDebug>
#include <QTime>
#include <QFile>

Singleton::Singleton()
{
    bytes_timer_.setParent(this);
    bytes_timer_.moveToThread(QThread::currentThread());
    bytes_timer_.setInterval(1000);
    qDebug() <<"Timeout success:" << connect(&bytes_timer_, &QTimer::timeout, this, [&]() {
        qDebug() <<"timeout";
        // . . .
    }, Qt::DirectConnection);
}

Singleton& Singleton::get_instance() {
    static Singleton instance;

    return instance;
}

void Singleton::start_client() {
    bytes_timer_.start();
}

void Singleton::stop_client() {
     bytes_timer_.stop();
}

QTimer Singleton::bytes_timer_;

MainWindow.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include"singleton.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    QThread thread;
    Singleton *s;
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

MainWindow.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include"mainwindow.h"
#include"ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    s = &Singleton::get_instance();
    s->moveToThread(&thread);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    thread.start();
    s->start_client();
}

main.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include"mainwindow.h"
#include <QApplication>
#include <QThread>
#include"singleton.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}


我以某种方式感到OP将会过度设计实际上可能非常简单的东西。

我做了一个MCVE来证明这一点。

testQTimerStartStop.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <QtWidgets>

int main(int argc, char **argv)
{
  qDebug() <<"Qt Version:" << QT_VERSION_STR;
  // prepare application
  QApplication app(argc, argv);
  QTimer qTimer;
  qTimer.setInterval(1000);
  // setup GUI
  QWidget qWinMain;
  qWinMain.setWindowTitle(QString::fromUtf8("QTimer Test"));
  QFormLayout qForm;
  QSpinBox qEditTimer;
  qEditTimer.setRange(0, 30);
  qForm.addRow(
    QString::fromUtf8("Count down:"),
    &qEditTimer);
  QPushButton qBtnStart(QString::fromUtf8("Start"));
  qForm.addRow(&qBtnStart);
  QPushButton qBtnStop(QString::fromUtf8("Stop"));
  qForm.addRow(&qBtnStop);
  qWinMain.setLayout(&qForm);
  qWinMain.show();
  // set initial states
  qEditTimer.setValue(10);
  auto updateBtns = [&]() {
    const int count = qEditTimer.value();
    qBtnStart.setEnabled(!qTimer.isActive() && count > 0);
    qBtnStop.setEnabled(qTimer.isActive());
  };
  updateBtns();
  // install signal handlers
  QObject::connect(&qTimer, &QTimer::timeout,
    [&]() {
      qEditTimer.setValue(qEditTimer.value() - 1); // count down
    });
  QObject::connect(&qEditTimer, (void (QSpinBox::*)(int))&QSpinBox::valueChanged,
    [&](int count) {
      if (count <= 0) qTimer.stop();
      updateBtns();
    });
  QObject::connect(&qBtnStart, &QPushButton::clicked,
    [&](bool) { qTimer.start(); updateBtns(); });
  QObject::connect(&qBtnStop, &QPushButton::clicked,
    [&](bool) { qTimer.stop(); updateBtns(); });
  // runtime loop
  return app.exec();
}

testQTimerStartStop.pro

1
2
3
SOURCES = testQTimerStartStop.cc

QT += widgets

构建并运行:

1
2
3
4
5
6
$ qmake-qt5 testQTimerStartStop.pro

$ make && ./testQTimerStartStop
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQTimerStartStop.o testQTimerStartStop.cc
g++  -o testQTimerStartStop.exe testQTimerStartStop.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4

Snapshot of testQTimerStartStop (animated)

QTimer移动到其他线程会增加很多开销。对QTimer的任何访问都具有

  • 在启动线程之前发生或
  • 被互斥保护
  • 通过信号(Qt::QueueConnection)完成。

我考虑了一下以适应我的样本方面,但是很快意识到了必要的努力并停止了。恕我直言,除非有充分的理由,否则我不建议您这样做。

请考虑以下事项:一个负载过大的应用程序会导致严重延迟超时信号的发出,而该应用程序可能无法很好地处理由另一个线程及时发出的超时事件。


如官方网站中所述,您需要启动计时器

1
bytes_timer_.start();

https://doc.qt.io/qt-5/qtimer.html#start-1