2

好的,所以我完全迷失在 QTimer 中。问题是:我有多线程应用程序,我需要对 QTimer 的超时做一些工作。我已经这样做了:

QTimer* timer = new QTimer();
timer->setSingleShot(true);
connect(timer, SIGNAL(timeout()), someObject, SLOT(work()));

这没有用。有时,work() 根本没有被调用,有时在我关闭程序时被调用,有时一切看起来都很正常。
所以我开始想到计时器需要线程。提供 MCV 示例:

class Tester : public QObject
{
 Q_OBJECT
 public:
 Tester(QObject* par = 0) : QObject(par)
 {
 }
 public slots:
 void greet()
 {
  qDebug()<<"hello";
 }
};

int main(int argc, char *argv[])
{
 QCoreApplication a(argc, argv);

 QTimer* timer1 = new QTimer();

 QThread* thread = new QThread();
 Tester* tester = new Tester();

 timer1->setInterval(500);
 timer1->setSingleShot(false);
 timer1->moveToThread(thread);


 QObject::connect(thread, SIGNAL(started()), timer1, SLOT(start()));

 QObject::connect(timer1, SIGNAL(timeout()), tester, SLOT(greet()));

 QObject::connect(timer1, SIGNAL(timeout()), timer1, SLOT(deleteLater()));
 QObject::connect(timer1, SIGNAL(destroyed()), thread, SLOT(quit()));

 thread->start();

 thread->wait();

 delete thread;
 delete tester;

 return a.exec();
}

这个例子什么也没做。它没有打招呼,所以没有调用超时,也没有结束,所以线程没有停止。所以问题是:
1. 这段代码有什么问题?
2.如何在多线程环境中正确使用QTimer?

4

1 回答 1

7

只是调用QTimer::setInterval不会启动 QTimer。它只是设置发出QTimer::timeout信号的时间间隔。您没有启动 QTimer。使用QTimer::start

我认为你在这里犯了几个错误。建立所有连接后,您需要将计时器移至线程。不确定在线程启动时启动计时器有多安全,因为此时计时器将在一个线程中,而线程对象将在另一个线程中。QTimer必须从创建它的同一线程开始。该QThread对象只是一个线程处理程序,它存在于创建的线程中。请参阅我对您的示例所做的修改:

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QTimer>
#include <QObject>

//#include "tester.h"

class Tester : public QObject
{
    Q_OBJECT

public:
    Tester(QObject* par = 0) : QObject(par)
    {
    }

public slots:
    void greet()
    {
        qDebug()<<"hello";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QTimer* timer1 = new QTimer();

    QThread* thread = new QThread();
    Tester* tester = new Tester();

    timer1->setInterval(500);
    timer1->setSingleShot(false);
    timer1->start();

    QObject::connect(timer1, SIGNAL(timeout()), tester, SLOT(greet()));

    timer1->moveToThread(thread);

    thread->start();

    return a.exec();
}

这不是最安全/最好的修复(内存泄漏和其他),但我希望它是您可以构建的示例。

在我看来,这是QTimer在另一个中使用 a 的正确且没有内存泄漏的方法QThread

处理程序.h

#ifndef HANDLER_H
#define HANDLER_H

#include <QObject>

class QTimer;
class QThread;
class Tester;

class Handler : public QObject
{
    Q_OBJECT

public:
    explicit Handler(QObject *parent = 0);
    ~Handler();

    void exec();

private:
    QTimer* timer;
    QThread* thread;
    Tester* tester;
};

#endif // HANDLER_H

处理程序.cpp

#include "handler.h"
#include "tester.h"

#include <QThread>
#include <QDebug>
#include <QTimer>
#include <QObject>
#include <QCoreApplication>

Handler::Handler(QObject *parent) :
    QObject(parent)
{
    timer = new QTimer;
    thread = new QThread(this);
    tester = new Tester(this);

    timer->setInterval(500);
    timer->setSingleShot(false);

    QObject::connect(timer, SIGNAL(timeout()), tester, SLOT(greet()));
    QObject::connect(thread, SIGNAL(destroyed()), timer, SLOT(deleteLater()));
}

Handler::~Handler()
{
    thread->wait();
}

void Handler::exec()
{
    timer->start();

    timer->moveToThread(thread);

    thread->start();
}

测试者.h

#ifndef TESTER_H
#define TESTER_H

#include <QObject>

class Tester : public QObject
{
    Q_OBJECT

public:
    Tester(QObject* par = 0);

public slots:
    void greet();
};


#endif // TESTER_H

测试器.cpp

#include "tester.h"

#include <QDebug>

Tester::Tester(QObject *parent) :
    QObject(parent)
{
}

void Tester::greet()
{
    qDebug()<<"hello";
}

主文件

#include <QCoreApplication>

#include "handler.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Handler handler;
    handler.exec();

    return a.exec();
}
于 2014-10-14T20:46:40.667 回答