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

これは最も安全な/最良の修正 (メモリ リークやその他) ではありませんが、構築できる例になることを願っています。

これは私の意見では、メモリリークなしで aQTimerを別の方法で使用するのが正しいと思います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();
}

tester.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

tester.cpp

#include "tester.h"

#include <QDebug>

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

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

main.cpp

#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 に答える