QThreadとmoveToThreadを使ってQTimerを別のスレッドで実行する方法です。
同スレッド上で重い処理を行う場合やSleepでの停止によるQTimerの実行周期ズレを回避します。
QTimerをmoveToThreadで別スレッド化
QTimer timer_th_;
QThread thread_timer_;
connect(&timer_th_, &QTimer::timeout, this, &MainWindow::timerTimeOutTh, Qt::DirectConnection);
timer_th_.setTimerType(Qt::PreciseTimer);
timer_th_.setInterval(1000);
timer_th_.start();
// 別スレッド化
timer_th_.moveToThread(&thread_timer_);
thread_timer_.start();
4行目は、QTimerのtimer_th_がタイムアウトした時に呼ばれるSLOTを設定しています。
connectの5番目の引数には、必ず「Qt:DirectConnection」を設定しましょう。
5行目、6行目がタイマーの設定で、7行目でタイマーをスタートしています。
9行目で、「moveToThread」を使って、timer_th_をthread_timer_上に移動します。そして、10行目でthread_timerをスタート。
以上で、QTimerを別のスレッドで動かすことができる様になります。
QThreadを使ってQTimerを別スレッドで動かすサンプル
簡単なプログラムを作成して動作の確認をしてみます。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <windows.h>
#include <iostream>
#include <string>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&timer_mw_, &QTimer::timeout, this, &MainWindow::timerTimeOutMw);
timer_mw_.setTimerType(Qt::PreciseTimer);
timer_mw_.setInterval(1000);
timer_mw_.start();
connect(&timer_th_, &QTimer::timeout, this, &MainWindow::timerTimeOutTh, Qt::DirectConnection);
timer_th_.setTimerType(Qt::PreciseTimer);
timer_th_.setInterval(1000);
timer_th_.start();
// 別スレッド化
timer_th_.moveToThread(&thread_timer_);
thread_timer_.start();
}
MainWindow::~MainWindow()
{
timer_mw_.stop();
timer_th_.stop();
thread_timer_.terminate();
delete ui;
}
void MainWindow::timerTimeOutTh()
{
// スレッドIDを出力する
std::cout << "timer_th_ timeout thread_id:" << GetCurrentThreadId() << std::endl;
}
void MainWindow::timerTimeOutMw()
{
// スレッドIDを出力する
std::cout << "timer_mw_ timeout thread_id:" << GetCurrentThreadId() << std::endl;
}
void MainWindow::on_pushButton_clicked()
{
Sleep(2000);
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QThread>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void timerTimeOutTh();
void timerTimeOutMw();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QThread thread_timer_;
QTimer timer_th_;
QTimer timer_mw_;
};
#endif // MAINWINDOW_H
mainwindow.cppの13~16行目がメインスレッドで動作するQTimerの設定、18~21行目がthread_timer_上で動作するQTimerの設定になっています。
どちらも1000ms周期で、スレッドIDを出力する処理が実行されます。
また、画面にボタンを配置して、ボタンが押された場合は、Sleep(2000)を実行してメインスレッドを2000msストップします。
実行すると、以下の様な結果が出力されます。
timer_mw_ timeout thread_id:11360
timer_th_ timeout thread_id:13928
timer_mw_ timeout thread_id:11360
timer_th_ timeout thread_id:13928
timer_th_ timeout thread_id:13928
timer_th_ timeout thread_id:13928
timer_mw_ timeout thread_id:11360
timer_mw_ timeout thread_id:11360
timer_th_ timeout thread_id:13928
3行目、4行目付近でボタンを押してメインスレッドが停止しているので、thread_timer_上で動作しているtimer_th_だけが動き続けています。
QThreadとmoveToThreadを使用すると、このように別スレッドでQTimerを動作させることができます。