QTimer :: timeout不触发

时间:2019-02-22 02:20:40

标签: c++ multithreading qt signals qtimer

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

Singleton.h:

#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:

#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:

#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:

#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:

#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();
}

2 个答案:

答案 0 :(得分:0)

官方网站上记录,您需要启动计时器

bytes_timer_.start();

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

答案 1 :(得分:0)

我某种程度上感觉到OP将会“过度设计”实际上可能非常简单的东西。

我做了MCVE来证明这一点。

testQTimerStartStop.cc

#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

SOURCES = testQTimerStartStop.cc

QT += widgets

构建并运行:

$ 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)完成。

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

请考虑:在高负载下导致超时信号发出明显延迟的应用程序可能无法很好地处理由另一个线程及时发出的超时事件。